blob: c283e5a4c1547d9d5685fb56f22a2fb9c59662e9 [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 Geoffray75d5b9b2015-10-05 07:40:35 +0000476 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
477 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100478 compiler_options,
479 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100480 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100481 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100482 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100483 move_resolver_(graph->GetArena(), this),
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000484 assembler_(),
Vladimir Marko58155012015-08-19 12:49:41 +0000485 isa_features_(isa_features),
Vladimir Marko5233f932015-09-29 19:01:15 +0100486 method_patches_(MethodReferenceComparator(),
487 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
488 call_patches_(MethodReferenceComparator(),
489 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
490 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700491 // Always save the LR register to mimic Quick.
492 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100493}
494
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000495void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
496 // Ensure that we fix up branches and literal loads and emit the literal pool.
497 __ FinalizeCode();
498
499 // Adjust native pc offsets in stack maps.
500 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
501 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
502 uint32_t new_position = __ GetAdjustedPosition(old_position);
503 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
504 }
505 // Adjust native pc offsets of block labels.
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100506 for (HBasicBlock* block : *block_order_) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000507 // Get the label directly from block_labels_ rather than through GetLabelOf() to avoid
508 // FirstNonEmptyBlock() which could lead to adjusting a label more than once.
Vladimir Marko225b6462015-09-28 12:17:40 +0100509 DCHECK_LT(block->GetBlockId(), GetGraph()->GetBlocks().size());
510 Label* block_label = &block_labels_[block->GetBlockId()];
David Brazdilfc6a86a2015-06-26 10:33:45 +0000511 DCHECK_EQ(block_label->IsBound(), !block->IsSingleJump());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000512 if (block_label->IsBound()) {
513 __ AdjustLabelPosition(block_label);
514 }
515 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100516 // Adjust pc offsets for the disassembly information.
517 if (disasm_info_ != nullptr) {
518 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
519 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
520 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
521 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
522 it.second.start = __ GetAdjustedPosition(it.second.start);
523 it.second.end = __ GetAdjustedPosition(it.second.end);
524 }
525 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
526 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
527 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
528 }
529 }
Vladimir Marko58155012015-08-19 12:49:41 +0000530 // Adjust pc offsets for relative call patches.
531 for (MethodPatchInfo<Label>& info : relative_call_patches_) {
532 __ AdjustLabelPosition(&info.label);
533 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000534
535 CodeGenerator::Finalize(allocator);
536}
537
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100538Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100539 switch (type) {
540 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100541 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100542 ArmManagedRegister pair =
543 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100544 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
545 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
546
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100547 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
548 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100549 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100550 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100551 }
552
553 case Primitive::kPrimByte:
554 case Primitive::kPrimBoolean:
555 case Primitive::kPrimChar:
556 case Primitive::kPrimShort:
557 case Primitive::kPrimInt:
558 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100559 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100560 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100561 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
562 ArmManagedRegister current =
563 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
564 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100565 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100566 }
567 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100568 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100569 }
570
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000571 case Primitive::kPrimFloat: {
572 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100573 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100574 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100575
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000576 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000577 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
578 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000579 return Location::FpuRegisterPairLocation(reg, reg + 1);
580 }
581
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100582 case Primitive::kPrimVoid:
583 LOG(FATAL) << "Unreachable type " << type;
584 }
585
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100586 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100587}
588
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000589void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100590 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100591 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100592
593 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100594 blocked_core_registers_[SP] = true;
595 blocked_core_registers_[LR] = true;
596 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100597
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100598 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100599 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100600
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100601 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100602 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100603
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000604 if (is_baseline) {
605 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
606 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
607 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000608
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000609 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
610
611 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
612 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
613 }
614 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100615
616 UpdateBlockedPairRegisters();
617}
618
619void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
620 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
621 ArmManagedRegister current =
622 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
623 if (blocked_core_registers_[current.AsRegisterPairLow()]
624 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
625 blocked_register_pairs_[i] = true;
626 }
627 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100628}
629
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100630InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
631 : HGraphVisitor(graph),
632 assembler_(codegen->GetAssembler()),
633 codegen_(codegen) {}
634
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000635void CodeGeneratorARM::ComputeSpillMask() {
636 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000637 // Save one extra register for baseline. Note that on thumb2, there is no easy
638 // instruction to restore just the PC, so this actually helps both baseline
639 // and non-baseline to save and restore at least two registers at entry and exit.
640 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000641 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
642 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
643 // We use vpush and vpop for saving and restoring floating point registers, which take
644 // a SRegister and the number of registers to save/restore after that SRegister. We
645 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
646 // but in the range.
647 if (fpu_spill_mask_ != 0) {
648 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
649 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
650 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
651 fpu_spill_mask_ |= (1 << i);
652 }
653 }
654}
655
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100656static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100657 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100658}
659
660static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100661 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100662}
663
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000664void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000665 bool skip_overflow_check =
666 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000667 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000668 __ Bind(&frame_entry_label_);
669
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000670 if (HasEmptyFrame()) {
671 return;
672 }
673
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100674 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000675 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
676 __ LoadFromOffset(kLoadWord, IP, IP, 0);
677 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100678 }
679
Andreas Gampe501fd632015-09-10 16:11:06 -0700680 __ PushList(core_spill_mask_);
681 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
682 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000683 if (fpu_spill_mask_ != 0) {
684 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
685 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100686 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100687 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000688 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100689 int adjust = GetFrameSize() - FrameEntrySpillSize();
690 __ AddConstant(SP, -adjust);
691 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100692 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000693}
694
695void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000696 if (HasEmptyFrame()) {
697 __ bx(LR);
698 return;
699 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100700 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100701 int adjust = GetFrameSize() - FrameEntrySpillSize();
702 __ AddConstant(SP, adjust);
703 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000704 if (fpu_spill_mask_ != 0) {
705 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
706 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100707 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
708 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000709 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700710 // Pop LR into PC to return.
711 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
712 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
713 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100714 __ cfi().RestoreState();
715 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000716}
717
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100718void CodeGeneratorARM::Bind(HBasicBlock* block) {
719 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000720}
721
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100722Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
723 switch (load->GetType()) {
724 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100725 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100726 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100727
728 case Primitive::kPrimInt:
729 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100730 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100731 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100732
733 case Primitive::kPrimBoolean:
734 case Primitive::kPrimByte:
735 case Primitive::kPrimChar:
736 case Primitive::kPrimShort:
737 case Primitive::kPrimVoid:
738 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700739 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100740 }
741
742 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700743 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100744}
745
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100746Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100747 switch (type) {
748 case Primitive::kPrimBoolean:
749 case Primitive::kPrimByte:
750 case Primitive::kPrimChar:
751 case Primitive::kPrimShort:
752 case Primitive::kPrimInt:
753 case Primitive::kPrimNot: {
754 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000755 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100756 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100757 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100758 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000759 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100760 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100761 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100762
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000763 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100764 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000765 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100766 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000767 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100768 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000769 if (calling_convention.GetRegisterAt(index) == R1) {
770 // Skip R1, and use R2_R3 instead.
771 gp_index_++;
772 index++;
773 }
774 }
775 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
776 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000777 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +0100778
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000779 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000780 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100781 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000782 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
783 }
784 }
785
786 case Primitive::kPrimFloat: {
787 uint32_t stack_index = stack_index_++;
788 if (float_index_ % 2 == 0) {
789 float_index_ = std::max(double_index_, float_index_);
790 }
791 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
792 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
793 } else {
794 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
795 }
796 }
797
798 case Primitive::kPrimDouble: {
799 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
800 uint32_t stack_index = stack_index_;
801 stack_index_ += 2;
802 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
803 uint32_t index = double_index_;
804 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000805 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000806 calling_convention.GetFpuRegisterAt(index),
807 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000808 DCHECK(ExpectedPairLayout(result));
809 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000810 } else {
811 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100812 }
813 }
814
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100815 case Primitive::kPrimVoid:
816 LOG(FATAL) << "Unexpected parameter type " << type;
817 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100818 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100819 return Location();
820}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100821
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100822Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000823 switch (type) {
824 case Primitive::kPrimBoolean:
825 case Primitive::kPrimByte:
826 case Primitive::kPrimChar:
827 case Primitive::kPrimShort:
828 case Primitive::kPrimInt:
829 case Primitive::kPrimNot: {
830 return Location::RegisterLocation(R0);
831 }
832
833 case Primitive::kPrimFloat: {
834 return Location::FpuRegisterLocation(S0);
835 }
836
837 case Primitive::kPrimLong: {
838 return Location::RegisterPairLocation(R0, R1);
839 }
840
841 case Primitive::kPrimDouble: {
842 return Location::FpuRegisterPairLocation(S0, S1);
843 }
844
845 case Primitive::kPrimVoid:
846 return Location();
847 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100848
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000849 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000850}
851
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100852Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
853 return Location::RegisterLocation(kMethodRegisterArgument);
854}
855
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100856void CodeGeneratorARM::Move32(Location destination, Location source) {
857 if (source.Equals(destination)) {
858 return;
859 }
860 if (destination.IsRegister()) {
861 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000862 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100863 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000864 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100865 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000866 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100867 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100868 } else if (destination.IsFpuRegister()) {
869 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000870 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100871 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000872 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100873 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000874 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100875 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100876 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000877 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100878 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000879 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100880 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000881 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100882 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000883 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100884 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
885 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100886 }
887 }
888}
889
890void CodeGeneratorARM::Move64(Location destination, Location source) {
891 if (source.Equals(destination)) {
892 return;
893 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100894 if (destination.IsRegisterPair()) {
895 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000896 EmitParallelMoves(
897 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
898 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100899 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000900 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100901 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
902 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100903 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000904 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +0100905 } else if (source.IsFpuRegisterPair()) {
906 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
907 destination.AsRegisterPairHigh<Register>(),
908 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
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());
Calin Juravlee460d1d2015-09-29 04:52:17 +0100920 } else if (source.IsRegisterPair()) {
921 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
922 source.AsRegisterPairLow<Register>(),
923 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100924 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000925 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100926 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100927 } else {
928 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100929 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000930 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100931 if (source.AsRegisterPairLow<Register>() == R1) {
932 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100933 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
934 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100935 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100936 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100937 SP, destination.GetStackIndex());
938 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000939 } else if (source.IsFpuRegisterPair()) {
940 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
941 SP,
942 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100943 } else {
944 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000945 EmitParallelMoves(
946 Location::StackSlot(source.GetStackIndex()),
947 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100948 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000949 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100950 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
951 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100952 }
953 }
954}
955
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100956void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100957 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100958 if (instruction->IsCurrentMethod()) {
959 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
960 } else if (locations != nullptr && locations->Out().Equals(location)) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100961 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100962 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000963 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000964 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
965 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +0000966 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000967 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000968 } else {
969 DCHECK(location.IsStackSlot());
970 __ LoadImmediate(IP, value);
971 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
972 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000973 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000974 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000975 int64_t value = const_to_move->AsLongConstant()->GetValue();
976 if (location.IsRegisterPair()) {
977 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
978 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
979 } else {
980 DCHECK(location.IsDoubleStackSlot());
981 __ LoadImmediate(IP, Low32Bits(value));
982 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
983 __ LoadImmediate(IP, High32Bits(value));
984 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
985 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100986 }
Roland Levillain476df552014-10-09 17:51:36 +0100987 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100988 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
989 switch (instruction->GetType()) {
990 case Primitive::kPrimBoolean:
991 case Primitive::kPrimByte:
992 case Primitive::kPrimChar:
993 case Primitive::kPrimShort:
994 case Primitive::kPrimInt:
995 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100996 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100997 Move32(location, Location::StackSlot(stack_slot));
998 break;
999
1000 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001001 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001002 Move64(location, Location::DoubleStackSlot(stack_slot));
1003 break;
1004
1005 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001006 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001007 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +00001008 } else if (instruction->IsTemporary()) {
1009 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +00001010 if (temp_location.IsStackSlot()) {
1011 Move32(location, temp_location);
1012 } else {
1013 DCHECK(temp_location.IsDoubleStackSlot());
1014 Move64(location, temp_location);
1015 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001016 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001017 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001018 switch (instruction->GetType()) {
1019 case Primitive::kPrimBoolean:
1020 case Primitive::kPrimByte:
1021 case Primitive::kPrimChar:
1022 case Primitive::kPrimShort:
1023 case Primitive::kPrimNot:
1024 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001025 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001026 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001027 break;
1028
1029 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001030 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001031 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001032 break;
1033
1034 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001035 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001036 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001037 }
1038}
1039
Calin Juravle175dc732015-08-25 15:42:32 +01001040void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1041 DCHECK(location.IsRegister());
1042 __ LoadImmediate(location.AsRegister<Register>(), value);
1043}
1044
Calin Juravlee460d1d2015-09-29 04:52:17 +01001045void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
1046 if (Primitive::Is64BitType(dst_type)) {
1047 Move64(dst, src);
1048 } else {
1049 Move32(dst, src);
1050 }
1051}
1052
1053void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1054 if (location.IsRegister()) {
1055 locations->AddTemp(location);
1056 } else if (location.IsRegisterPair()) {
1057 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1058 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1059 } else {
1060 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1061 }
1062}
1063
Calin Juravle175dc732015-08-25 15:42:32 +01001064void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1065 HInstruction* instruction,
1066 uint32_t dex_pc,
1067 SlowPathCode* slow_path) {
1068 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
1069 instruction,
1070 dex_pc,
1071 slow_path);
1072}
1073
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001074void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1075 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001076 uint32_t dex_pc,
1077 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001078 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001079 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1080 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001081 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001082}
1083
David Brazdilfc6a86a2015-06-26 10:33:45 +00001084void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001085 DCHECK(!successor->IsExitBlock());
1086
1087 HBasicBlock* block = got->GetBlock();
1088 HInstruction* previous = got->GetPrevious();
1089
1090 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001091 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001092 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1093 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1094 return;
1095 }
1096
1097 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1098 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1099 }
1100 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001101 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001102 }
1103}
1104
David Brazdilfc6a86a2015-06-26 10:33:45 +00001105void LocationsBuilderARM::VisitGoto(HGoto* got) {
1106 got->SetLocations(nullptr);
1107}
1108
1109void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1110 HandleGoto(got, got->GetSuccessor());
1111}
1112
1113void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1114 try_boundary->SetLocations(nullptr);
1115}
1116
1117void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1118 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1119 if (!successor->IsExitBlock()) {
1120 HandleGoto(try_boundary, successor);
1121 }
1122}
1123
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001124void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001125 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001126}
1127
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001128void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001129 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001130}
1131
Roland Levillain4fa13f62015-07-06 18:11:54 +01001132void InstructionCodeGeneratorARM::GenerateCompareWithImmediate(Register left, int32_t right) {
1133 ShifterOperand operand;
1134 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, right, &operand)) {
1135 __ cmp(left, operand);
1136 } else {
1137 Register temp = IP;
1138 __ LoadImmediate(temp, right);
1139 __ cmp(left, ShifterOperand(temp));
1140 }
1141}
1142
1143void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1144 Label* true_label,
1145 Label* false_label) {
1146 __ vmstat(); // transfer FP status register to ARM APSR.
1147 if (cond->IsFPConditionTrueIfNaN()) {
1148 __ b(true_label, VS); // VS for unordered.
1149 } else if (cond->IsFPConditionFalseIfNaN()) {
1150 __ b(false_label, VS); // VS for unordered.
1151 }
1152 __ b(true_label, ARMSignedOrFPCondition(cond->GetCondition()));
1153}
1154
1155void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1156 Label* true_label,
1157 Label* false_label) {
1158 LocationSummary* locations = cond->GetLocations();
1159 Location left = locations->InAt(0);
1160 Location right = locations->InAt(1);
1161 IfCondition if_cond = cond->GetCondition();
1162
1163 Register left_high = left.AsRegisterPairHigh<Register>();
1164 Register left_low = left.AsRegisterPairLow<Register>();
1165 IfCondition true_high_cond = if_cond;
1166 IfCondition false_high_cond = cond->GetOppositeCondition();
1167 Condition final_condition = ARMUnsignedCondition(if_cond);
1168
1169 // Set the conditions for the test, remembering that == needs to be
1170 // decided using the low words.
1171 switch (if_cond) {
1172 case kCondEQ:
1173 case kCondNE:
1174 // Nothing to do.
1175 break;
1176 case kCondLT:
1177 false_high_cond = kCondGT;
1178 break;
1179 case kCondLE:
1180 true_high_cond = kCondLT;
1181 break;
1182 case kCondGT:
1183 false_high_cond = kCondLT;
1184 break;
1185 case kCondGE:
1186 true_high_cond = kCondGT;
1187 break;
1188 }
1189 if (right.IsConstant()) {
1190 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1191 int32_t val_low = Low32Bits(value);
1192 int32_t val_high = High32Bits(value);
1193
1194 GenerateCompareWithImmediate(left_high, val_high);
1195 if (if_cond == kCondNE) {
1196 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1197 } else if (if_cond == kCondEQ) {
1198 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1199 } else {
1200 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1201 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1202 }
1203 // Must be equal high, so compare the lows.
1204 GenerateCompareWithImmediate(left_low, val_low);
1205 } else {
1206 Register right_high = right.AsRegisterPairHigh<Register>();
1207 Register right_low = right.AsRegisterPairLow<Register>();
1208
1209 __ cmp(left_high, ShifterOperand(right_high));
1210 if (if_cond == kCondNE) {
1211 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1212 } else if (if_cond == kCondEQ) {
1213 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1214 } else {
1215 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1216 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1217 }
1218 // Must be equal high, so compare the lows.
1219 __ cmp(left_low, ShifterOperand(right_low));
1220 }
1221 // The last comparison might be unsigned.
1222 __ b(true_label, final_condition);
1223}
1224
1225void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HIf* if_instr,
1226 HCondition* condition,
1227 Label* true_target,
1228 Label* false_target,
1229 Label* always_true_target) {
1230 LocationSummary* locations = condition->GetLocations();
1231 Location left = locations->InAt(0);
1232 Location right = locations->InAt(1);
1233
1234 // We don't want true_target as a nullptr.
1235 if (true_target == nullptr) {
1236 true_target = always_true_target;
1237 }
1238 bool falls_through = (false_target == nullptr);
1239
1240 // FP compares don't like null false_targets.
1241 if (false_target == nullptr) {
1242 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1243 }
1244
1245 Primitive::Type type = condition->InputAt(0)->GetType();
1246 switch (type) {
1247 case Primitive::kPrimLong:
1248 GenerateLongComparesAndJumps(condition, true_target, false_target);
1249 break;
1250 case Primitive::kPrimFloat:
1251 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1252 GenerateFPJumps(condition, true_target, false_target);
1253 break;
1254 case Primitive::kPrimDouble:
1255 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1256 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1257 GenerateFPJumps(condition, true_target, false_target);
1258 break;
1259 default:
1260 LOG(FATAL) << "Unexpected compare type " << type;
1261 }
1262
1263 if (!falls_through) {
1264 __ b(false_target);
1265 }
1266}
1267
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001268void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
1269 Label* true_target,
1270 Label* false_target,
1271 Label* always_true_target) {
1272 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001273 if (cond->IsIntConstant()) {
1274 // Constant condition, statically compared against 1.
1275 int32_t cond_value = cond->AsIntConstant()->GetValue();
1276 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001277 if (always_true_target != nullptr) {
1278 __ b(always_true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001279 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001280 return;
1281 } else {
1282 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001283 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001284 } else {
1285 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1286 // Condition has been materialized, compare the output to 0
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001287 DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01001288 __ CompareAndBranchIfNonZero(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
1289 true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001290 } else {
1291 // Condition has not been materialized, use its inputs as the
1292 // comparison and its condition as the branch condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001293 Primitive::Type type =
1294 cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
1295 // Is this a long or FP comparison that has been folded into the HCondition?
1296 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1297 // Generate the comparison directly.
1298 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
1299 true_target, false_target, always_true_target);
1300 return;
1301 }
1302
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001303 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001304 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001305 Register left = locations->InAt(0).AsRegister<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001306 Location right = locations->InAt(1);
1307 if (right.IsRegister()) {
1308 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001309 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001310 DCHECK(right.IsConstant());
1311 GenerateCompareWithImmediate(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001312 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001313 __ b(true_target, ARMSignedOrFPCondition(cond->AsCondition()->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001314 }
Dave Allison20dfc792014-06-16 20:44:29 -07001315 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001316 if (false_target != nullptr) {
1317 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001318 }
1319}
1320
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001321void LocationsBuilderARM::VisitIf(HIf* if_instr) {
1322 LocationSummary* locations =
1323 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1324 HInstruction* cond = if_instr->InputAt(0);
1325 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1326 locations->SetInAt(0, Location::RequiresRegister());
1327 }
1328}
1329
1330void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
1331 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1332 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1333 Label* always_true_target = true_target;
1334 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1335 if_instr->IfTrueSuccessor())) {
1336 always_true_target = nullptr;
1337 }
1338 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1339 if_instr->IfFalseSuccessor())) {
1340 false_target = nullptr;
1341 }
1342 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1343}
1344
1345void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1346 LocationSummary* locations = new (GetGraph()->GetArena())
1347 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1348 HInstruction* cond = deoptimize->InputAt(0);
1349 DCHECK(cond->IsCondition());
1350 if (cond->AsCondition()->NeedsMaterialization()) {
1351 locations->SetInAt(0, Location::RequiresRegister());
1352 }
1353}
1354
1355void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001356 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001357 DeoptimizationSlowPathARM(deoptimize);
1358 codegen_->AddSlowPath(slow_path);
1359 Label* slow_path_entry = slow_path->GetEntryLabel();
1360 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1361}
Dave Allison20dfc792014-06-16 20:44:29 -07001362
Roland Levillain0d37cd02015-05-27 16:39:19 +01001363void LocationsBuilderARM::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001364 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001365 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001366 // Handle the long/FP comparisons made in instruction simplification.
1367 switch (cond->InputAt(0)->GetType()) {
1368 case Primitive::kPrimLong:
1369 locations->SetInAt(0, Location::RequiresRegister());
1370 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1371 if (cond->NeedsMaterialization()) {
1372 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1373 }
1374 break;
1375
1376 case Primitive::kPrimFloat:
1377 case Primitive::kPrimDouble:
1378 locations->SetInAt(0, Location::RequiresFpuRegister());
1379 locations->SetInAt(1, Location::RequiresFpuRegister());
1380 if (cond->NeedsMaterialization()) {
1381 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1382 }
1383 break;
1384
1385 default:
1386 locations->SetInAt(0, Location::RequiresRegister());
1387 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1388 if (cond->NeedsMaterialization()) {
1389 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1390 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001391 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001392}
1393
Roland Levillain0d37cd02015-05-27 16:39:19 +01001394void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001395 if (!cond->NeedsMaterialization()) {
1396 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001397 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001398
1399 LocationSummary* locations = cond->GetLocations();
1400 Location left = locations->InAt(0);
1401 Location right = locations->InAt(1);
1402 Register out = locations->Out().AsRegister<Register>();
1403 Label true_label, false_label;
1404
1405 switch (cond->InputAt(0)->GetType()) {
1406 default: {
1407 // Integer case.
1408 if (right.IsRegister()) {
1409 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1410 } else {
1411 DCHECK(right.IsConstant());
1412 GenerateCompareWithImmediate(left.AsRegister<Register>(),
1413 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1414 }
1415 __ it(ARMSignedOrFPCondition(cond->GetCondition()), kItElse);
1416 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
1417 ARMSignedOrFPCondition(cond->GetCondition()));
1418 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
1419 ARMSignedOrFPCondition(cond->GetOppositeCondition()));
1420 return;
1421 }
1422 case Primitive::kPrimLong:
1423 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1424 break;
1425 case Primitive::kPrimFloat:
1426 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1427 GenerateFPJumps(cond, &true_label, &false_label);
1428 break;
1429 case Primitive::kPrimDouble:
1430 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1431 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1432 GenerateFPJumps(cond, &true_label, &false_label);
1433 break;
1434 }
1435
1436 // Convert the jumps into the result.
1437 Label done_label;
1438
1439 // False case: result = 0.
1440 __ Bind(&false_label);
1441 __ LoadImmediate(out, 0);
1442 __ b(&done_label);
1443
1444 // True case: result = 1.
1445 __ Bind(&true_label);
1446 __ LoadImmediate(out, 1);
1447 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001448}
1449
1450void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1451 VisitCondition(comp);
1452}
1453
1454void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1455 VisitCondition(comp);
1456}
1457
1458void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1459 VisitCondition(comp);
1460}
1461
1462void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1463 VisitCondition(comp);
1464}
1465
1466void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1467 VisitCondition(comp);
1468}
1469
1470void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1471 VisitCondition(comp);
1472}
1473
1474void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1475 VisitCondition(comp);
1476}
1477
1478void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1479 VisitCondition(comp);
1480}
1481
1482void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1483 VisitCondition(comp);
1484}
1485
1486void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1487 VisitCondition(comp);
1488}
1489
1490void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1491 VisitCondition(comp);
1492}
1493
1494void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1495 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001496}
1497
1498void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001499 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001500}
1501
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001502void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1503 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001504}
1505
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001506void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001507 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001508}
1509
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001510void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001511 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001512 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001513}
1514
1515void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001516 LocationSummary* locations =
1517 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001518 switch (store->InputAt(1)->GetType()) {
1519 case Primitive::kPrimBoolean:
1520 case Primitive::kPrimByte:
1521 case Primitive::kPrimChar:
1522 case Primitive::kPrimShort:
1523 case Primitive::kPrimInt:
1524 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001525 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001526 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1527 break;
1528
1529 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001530 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001531 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1532 break;
1533
1534 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001535 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001536 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001537}
1538
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001539void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001540 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001541}
1542
1543void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001544 LocationSummary* locations =
1545 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001546 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001547}
1548
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001549void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001550 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001551 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001552}
1553
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001554void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1555 LocationSummary* locations =
1556 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1557 locations->SetOut(Location::ConstantLocation(constant));
1558}
1559
1560void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
1561 // Will be generated at use site.
1562 UNUSED(constant);
1563}
1564
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001565void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001566 LocationSummary* locations =
1567 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001568 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001569}
1570
1571void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1572 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001573 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001574}
1575
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001576void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1577 LocationSummary* locations =
1578 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1579 locations->SetOut(Location::ConstantLocation(constant));
1580}
1581
1582void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1583 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001584 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001585}
1586
1587void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1588 LocationSummary* locations =
1589 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1590 locations->SetOut(Location::ConstantLocation(constant));
1591}
1592
1593void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1594 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001595 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001596}
1597
Calin Juravle27df7582015-04-17 19:12:31 +01001598void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1599 memory_barrier->SetLocations(nullptr);
1600}
1601
1602void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1603 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1604}
1605
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001606void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001607 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001608}
1609
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001610void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001611 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001612 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001613}
1614
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001615void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001616 LocationSummary* locations =
1617 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001618 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001619}
1620
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001621void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001622 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001623 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001624}
1625
Calin Juravle175dc732015-08-25 15:42:32 +01001626void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1627 // The trampoline uses the same calling convention as dex calling conventions,
1628 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1629 // the method_idx.
1630 HandleInvoke(invoke);
1631}
1632
1633void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1634 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1635}
1636
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001637void LocationsBuilderARM::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 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1643 codegen_->GetInstructionSetFeatures());
1644 if (intrinsic.TryDispatch(invoke)) {
1645 return;
1646 }
1647
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001648 HandleInvoke(invoke);
1649}
1650
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001651static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1652 if (invoke->GetLocations()->Intrinsified()) {
1653 IntrinsicCodeGeneratorARM intrinsic(codegen);
1654 intrinsic.Dispatch(invoke);
1655 return true;
1656 }
1657 return false;
1658}
1659
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001660void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001661 // When we do not run baseline, explicit clinit checks triggered by static
1662 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1663 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001664
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001665 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1666 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001667 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001668
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001669 LocationSummary* locations = invoke->GetLocations();
1670 codegen_->GenerateStaticOrDirectCall(
1671 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001672 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001673}
1674
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001675void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001676 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001677 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001678}
1679
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001680void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001681 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1682 codegen_->GetInstructionSetFeatures());
1683 if (intrinsic.TryDispatch(invoke)) {
1684 return;
1685 }
1686
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001687 HandleInvoke(invoke);
1688}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001689
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001690void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001691 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1692 return;
1693 }
1694
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001695 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001696 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001697 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001698}
1699
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001700void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1701 HandleInvoke(invoke);
1702 // Add the hidden argument.
1703 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1704}
1705
1706void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1707 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001708 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001709 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1710 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001711 LocationSummary* locations = invoke->GetLocations();
1712 Location receiver = locations->InAt(0);
1713 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1714
1715 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001716 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1717 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001718
1719 // temp = object->GetClass();
1720 if (receiver.IsStackSlot()) {
1721 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1722 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1723 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001724 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001725 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001726 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001727 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001728 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001729 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001730 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001731 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1732 // LR = temp->GetEntryPoint();
1733 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1734 // LR();
1735 __ blx(LR);
1736 DCHECK(!codegen_->IsLeafMethod());
1737 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1738}
1739
Roland Levillain88cb1752014-10-20 16:36:47 +01001740void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1741 LocationSummary* locations =
1742 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1743 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001744 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001745 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001746 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1747 break;
1748 }
1749 case Primitive::kPrimLong: {
1750 locations->SetInAt(0, Location::RequiresRegister());
1751 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001752 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001753 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001754
Roland Levillain88cb1752014-10-20 16:36:47 +01001755 case Primitive::kPrimFloat:
1756 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001757 locations->SetInAt(0, Location::RequiresFpuRegister());
1758 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001759 break;
1760
1761 default:
1762 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1763 }
1764}
1765
1766void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1767 LocationSummary* locations = neg->GetLocations();
1768 Location out = locations->Out();
1769 Location in = locations->InAt(0);
1770 switch (neg->GetResultType()) {
1771 case Primitive::kPrimInt:
1772 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001773 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001774 break;
1775
1776 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001777 DCHECK(in.IsRegisterPair());
1778 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1779 __ rsbs(out.AsRegisterPairLow<Register>(),
1780 in.AsRegisterPairLow<Register>(),
1781 ShifterOperand(0));
1782 // We cannot emit an RSC (Reverse Subtract with Carry)
1783 // instruction here, as it does not exist in the Thumb-2
1784 // instruction set. We use the following approach
1785 // using SBC and SUB instead.
1786 //
1787 // out.hi = -C
1788 __ sbc(out.AsRegisterPairHigh<Register>(),
1789 out.AsRegisterPairHigh<Register>(),
1790 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1791 // out.hi = out.hi - in.hi
1792 __ sub(out.AsRegisterPairHigh<Register>(),
1793 out.AsRegisterPairHigh<Register>(),
1794 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1795 break;
1796
Roland Levillain88cb1752014-10-20 16:36:47 +01001797 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001798 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001799 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001800 break;
1801
Roland Levillain88cb1752014-10-20 16:36:47 +01001802 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001803 DCHECK(in.IsFpuRegisterPair());
1804 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1805 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001806 break;
1807
1808 default:
1809 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1810 }
1811}
1812
Roland Levillaindff1f282014-11-05 14:15:05 +00001813void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001814 Primitive::Type result_type = conversion->GetResultType();
1815 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001816 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001817
Roland Levillain5b3ee562015-04-14 16:02:41 +01001818 // The float-to-long, double-to-long and long-to-float type conversions
1819 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001820 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01001821 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1822 && result_type == Primitive::kPrimLong)
1823 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00001824 ? LocationSummary::kCall
1825 : LocationSummary::kNoCall;
1826 LocationSummary* locations =
1827 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1828
David Brazdilb2bd1c52015-03-25 11:17:37 +00001829 // The Java language does not allow treating boolean as an integral type but
1830 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001831
Roland Levillaindff1f282014-11-05 14:15:05 +00001832 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001833 case Primitive::kPrimByte:
1834 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001835 case Primitive::kPrimBoolean:
1836 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001837 case Primitive::kPrimShort:
1838 case Primitive::kPrimInt:
1839 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001840 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001841 locations->SetInAt(0, Location::RequiresRegister());
1842 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1843 break;
1844
1845 default:
1846 LOG(FATAL) << "Unexpected type conversion from " << input_type
1847 << " to " << result_type;
1848 }
1849 break;
1850
Roland Levillain01a8d712014-11-14 16:27:39 +00001851 case Primitive::kPrimShort:
1852 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001853 case Primitive::kPrimBoolean:
1854 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001855 case Primitive::kPrimByte:
1856 case Primitive::kPrimInt:
1857 case Primitive::kPrimChar:
1858 // Processing a Dex `int-to-short' instruction.
1859 locations->SetInAt(0, Location::RequiresRegister());
1860 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1861 break;
1862
1863 default:
1864 LOG(FATAL) << "Unexpected type conversion from " << input_type
1865 << " to " << result_type;
1866 }
1867 break;
1868
Roland Levillain946e1432014-11-11 17:35:19 +00001869 case Primitive::kPrimInt:
1870 switch (input_type) {
1871 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001872 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001873 locations->SetInAt(0, Location::Any());
1874 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1875 break;
1876
1877 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001878 // Processing a Dex `float-to-int' instruction.
1879 locations->SetInAt(0, Location::RequiresFpuRegister());
1880 locations->SetOut(Location::RequiresRegister());
1881 locations->AddTemp(Location::RequiresFpuRegister());
1882 break;
1883
Roland Levillain946e1432014-11-11 17:35:19 +00001884 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001885 // Processing a Dex `double-to-int' instruction.
1886 locations->SetInAt(0, Location::RequiresFpuRegister());
1887 locations->SetOut(Location::RequiresRegister());
1888 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001889 break;
1890
1891 default:
1892 LOG(FATAL) << "Unexpected type conversion from " << input_type
1893 << " to " << result_type;
1894 }
1895 break;
1896
Roland Levillaindff1f282014-11-05 14:15:05 +00001897 case Primitive::kPrimLong:
1898 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001899 case Primitive::kPrimBoolean:
1900 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001901 case Primitive::kPrimByte:
1902 case Primitive::kPrimShort:
1903 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001904 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001905 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001906 locations->SetInAt(0, Location::RequiresRegister());
1907 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1908 break;
1909
Roland Levillain624279f2014-12-04 11:54:28 +00001910 case Primitive::kPrimFloat: {
1911 // Processing a Dex `float-to-long' instruction.
1912 InvokeRuntimeCallingConvention calling_convention;
1913 locations->SetInAt(0, Location::FpuRegisterLocation(
1914 calling_convention.GetFpuRegisterAt(0)));
1915 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1916 break;
1917 }
1918
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001919 case Primitive::kPrimDouble: {
1920 // Processing a Dex `double-to-long' instruction.
1921 InvokeRuntimeCallingConvention calling_convention;
1922 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1923 calling_convention.GetFpuRegisterAt(0),
1924 calling_convention.GetFpuRegisterAt(1)));
1925 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001926 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001927 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001928
1929 default:
1930 LOG(FATAL) << "Unexpected type conversion from " << input_type
1931 << " to " << result_type;
1932 }
1933 break;
1934
Roland Levillain981e4542014-11-14 11:47:14 +00001935 case Primitive::kPrimChar:
1936 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001937 case Primitive::kPrimBoolean:
1938 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001939 case Primitive::kPrimByte:
1940 case Primitive::kPrimShort:
1941 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001942 // Processing a Dex `int-to-char' instruction.
1943 locations->SetInAt(0, Location::RequiresRegister());
1944 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1945 break;
1946
1947 default:
1948 LOG(FATAL) << "Unexpected type conversion from " << input_type
1949 << " to " << result_type;
1950 }
1951 break;
1952
Roland Levillaindff1f282014-11-05 14:15:05 +00001953 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001954 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001955 case Primitive::kPrimBoolean:
1956 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001957 case Primitive::kPrimByte:
1958 case Primitive::kPrimShort:
1959 case Primitive::kPrimInt:
1960 case Primitive::kPrimChar:
1961 // Processing a Dex `int-to-float' instruction.
1962 locations->SetInAt(0, Location::RequiresRegister());
1963 locations->SetOut(Location::RequiresFpuRegister());
1964 break;
1965
Roland Levillain5b3ee562015-04-14 16:02:41 +01001966 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00001967 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01001968 InvokeRuntimeCallingConvention calling_convention;
1969 locations->SetInAt(0, Location::RegisterPairLocation(
1970 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
1971 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00001972 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01001973 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00001974
Roland Levillaincff13742014-11-17 14:32:17 +00001975 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001976 // Processing a Dex `double-to-float' instruction.
1977 locations->SetInAt(0, Location::RequiresFpuRegister());
1978 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001979 break;
1980
1981 default:
1982 LOG(FATAL) << "Unexpected type conversion from " << input_type
1983 << " to " << result_type;
1984 };
1985 break;
1986
Roland Levillaindff1f282014-11-05 14:15:05 +00001987 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001988 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001989 case Primitive::kPrimBoolean:
1990 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001991 case Primitive::kPrimByte:
1992 case Primitive::kPrimShort:
1993 case Primitive::kPrimInt:
1994 case Primitive::kPrimChar:
1995 // Processing a Dex `int-to-double' instruction.
1996 locations->SetInAt(0, Location::RequiresRegister());
1997 locations->SetOut(Location::RequiresFpuRegister());
1998 break;
1999
2000 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002001 // Processing a Dex `long-to-double' instruction.
2002 locations->SetInAt(0, Location::RequiresRegister());
2003 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01002004 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002005 locations->AddTemp(Location::RequiresFpuRegister());
2006 break;
2007
Roland Levillaincff13742014-11-17 14:32:17 +00002008 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002009 // Processing a Dex `float-to-double' instruction.
2010 locations->SetInAt(0, Location::RequiresFpuRegister());
2011 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002012 break;
2013
2014 default:
2015 LOG(FATAL) << "Unexpected type conversion from " << input_type
2016 << " to " << result_type;
2017 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002018 break;
2019
2020 default:
2021 LOG(FATAL) << "Unexpected type conversion from " << input_type
2022 << " to " << result_type;
2023 }
2024}
2025
2026void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2027 LocationSummary* locations = conversion->GetLocations();
2028 Location out = locations->Out();
2029 Location in = locations->InAt(0);
2030 Primitive::Type result_type = conversion->GetResultType();
2031 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002032 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002033 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002034 case Primitive::kPrimByte:
2035 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002036 case Primitive::kPrimBoolean:
2037 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002038 case Primitive::kPrimShort:
2039 case Primitive::kPrimInt:
2040 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002041 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002042 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002043 break;
2044
2045 default:
2046 LOG(FATAL) << "Unexpected type conversion from " << input_type
2047 << " to " << result_type;
2048 }
2049 break;
2050
Roland Levillain01a8d712014-11-14 16:27:39 +00002051 case Primitive::kPrimShort:
2052 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002053 case Primitive::kPrimBoolean:
2054 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002055 case Primitive::kPrimByte:
2056 case Primitive::kPrimInt:
2057 case Primitive::kPrimChar:
2058 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002059 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002060 break;
2061
2062 default:
2063 LOG(FATAL) << "Unexpected type conversion from " << input_type
2064 << " to " << result_type;
2065 }
2066 break;
2067
Roland Levillain946e1432014-11-11 17:35:19 +00002068 case Primitive::kPrimInt:
2069 switch (input_type) {
2070 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002071 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002072 DCHECK(out.IsRegister());
2073 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002074 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002075 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002076 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002077 } else {
2078 DCHECK(in.IsConstant());
2079 DCHECK(in.GetConstant()->IsLongConstant());
2080 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002081 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002082 }
2083 break;
2084
Roland Levillain3f8f9362014-12-02 17:45:01 +00002085 case Primitive::kPrimFloat: {
2086 // Processing a Dex `float-to-int' instruction.
2087 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2088 __ vmovs(temp, in.AsFpuRegister<SRegister>());
2089 __ vcvtis(temp, temp);
2090 __ vmovrs(out.AsRegister<Register>(), temp);
2091 break;
2092 }
2093
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002094 case Primitive::kPrimDouble: {
2095 // Processing a Dex `double-to-int' instruction.
2096 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2097 DRegister temp_d = FromLowSToD(temp_s);
2098 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2099 __ vcvtid(temp_s, temp_d);
2100 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002101 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002102 }
Roland Levillain946e1432014-11-11 17:35:19 +00002103
2104 default:
2105 LOG(FATAL) << "Unexpected type conversion from " << input_type
2106 << " to " << result_type;
2107 }
2108 break;
2109
Roland Levillaindff1f282014-11-05 14:15:05 +00002110 case Primitive::kPrimLong:
2111 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002112 case Primitive::kPrimBoolean:
2113 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002114 case Primitive::kPrimByte:
2115 case Primitive::kPrimShort:
2116 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002117 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002118 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002119 DCHECK(out.IsRegisterPair());
2120 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002121 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002122 // Sign extension.
2123 __ Asr(out.AsRegisterPairHigh<Register>(),
2124 out.AsRegisterPairLow<Register>(),
2125 31);
2126 break;
2127
2128 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002129 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002130 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2131 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002132 conversion->GetDexPc(),
2133 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002134 break;
2135
Roland Levillaindff1f282014-11-05 14:15:05 +00002136 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002137 // Processing a Dex `double-to-long' instruction.
2138 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2139 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002140 conversion->GetDexPc(),
2141 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002142 break;
2143
2144 default:
2145 LOG(FATAL) << "Unexpected type conversion from " << input_type
2146 << " to " << result_type;
2147 }
2148 break;
2149
Roland Levillain981e4542014-11-14 11:47:14 +00002150 case Primitive::kPrimChar:
2151 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002152 case Primitive::kPrimBoolean:
2153 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002154 case Primitive::kPrimByte:
2155 case Primitive::kPrimShort:
2156 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002157 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002158 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002159 break;
2160
2161 default:
2162 LOG(FATAL) << "Unexpected type conversion from " << input_type
2163 << " to " << result_type;
2164 }
2165 break;
2166
Roland Levillaindff1f282014-11-05 14:15:05 +00002167 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002168 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002169 case Primitive::kPrimBoolean:
2170 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002171 case Primitive::kPrimByte:
2172 case Primitive::kPrimShort:
2173 case Primitive::kPrimInt:
2174 case Primitive::kPrimChar: {
2175 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002176 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2177 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002178 break;
2179 }
2180
Roland Levillain5b3ee562015-04-14 16:02:41 +01002181 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002182 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002183 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2184 conversion,
2185 conversion->GetDexPc(),
2186 nullptr);
Roland Levillain6d0e4832014-11-27 18:31:21 +00002187 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002188
Roland Levillaincff13742014-11-17 14:32:17 +00002189 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002190 // Processing a Dex `double-to-float' instruction.
2191 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2192 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002193 break;
2194
2195 default:
2196 LOG(FATAL) << "Unexpected type conversion from " << input_type
2197 << " to " << result_type;
2198 };
2199 break;
2200
Roland Levillaindff1f282014-11-05 14:15:05 +00002201 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002202 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002203 case Primitive::kPrimBoolean:
2204 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002205 case Primitive::kPrimByte:
2206 case Primitive::kPrimShort:
2207 case Primitive::kPrimInt:
2208 case Primitive::kPrimChar: {
2209 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002210 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002211 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2212 out.AsFpuRegisterPairLow<SRegister>());
2213 break;
2214 }
2215
Roland Levillain647b9ed2014-11-27 12:06:00 +00002216 case Primitive::kPrimLong: {
2217 // Processing a Dex `long-to-double' instruction.
2218 Register low = in.AsRegisterPairLow<Register>();
2219 Register high = in.AsRegisterPairHigh<Register>();
2220 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2221 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002222 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002223 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002224 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2225 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002226
Roland Levillain682393c2015-04-14 15:57:52 +01002227 // temp_d = int-to-double(high)
2228 __ vmovsr(temp_s, high);
2229 __ vcvtdi(temp_d, temp_s);
2230 // constant_d = k2Pow32EncodingForDouble
2231 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2232 // out_d = unsigned-to-double(low)
2233 __ vmovsr(out_s, low);
2234 __ vcvtdu(out_d, out_s);
2235 // out_d += temp_d * constant_d
2236 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002237 break;
2238 }
2239
Roland Levillaincff13742014-11-17 14:32:17 +00002240 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002241 // Processing a Dex `float-to-double' instruction.
2242 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2243 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002244 break;
2245
2246 default:
2247 LOG(FATAL) << "Unexpected type conversion from " << input_type
2248 << " to " << result_type;
2249 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002250 break;
2251
2252 default:
2253 LOG(FATAL) << "Unexpected type conversion from " << input_type
2254 << " to " << result_type;
2255 }
2256}
2257
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002258void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002259 LocationSummary* locations =
2260 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002261 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002262 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002263 locations->SetInAt(0, Location::RequiresRegister());
2264 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002265 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2266 break;
2267 }
2268
2269 case Primitive::kPrimLong: {
2270 locations->SetInAt(0, Location::RequiresRegister());
2271 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002272 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002273 break;
2274 }
2275
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002276 case Primitive::kPrimFloat:
2277 case Primitive::kPrimDouble: {
2278 locations->SetInAt(0, Location::RequiresFpuRegister());
2279 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002280 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002281 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002282 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002283
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002284 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002285 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002286 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002287}
2288
2289void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2290 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002291 Location out = locations->Out();
2292 Location first = locations->InAt(0);
2293 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002294 switch (add->GetResultType()) {
2295 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002296 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002297 __ add(out.AsRegister<Register>(),
2298 first.AsRegister<Register>(),
2299 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002300 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002301 __ AddConstant(out.AsRegister<Register>(),
2302 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002303 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002304 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002305 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002306
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002307 case Primitive::kPrimLong: {
2308 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002309 __ adds(out.AsRegisterPairLow<Register>(),
2310 first.AsRegisterPairLow<Register>(),
2311 ShifterOperand(second.AsRegisterPairLow<Register>()));
2312 __ adc(out.AsRegisterPairHigh<Register>(),
2313 first.AsRegisterPairHigh<Register>(),
2314 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002315 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002316 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002317
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002318 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002319 __ vadds(out.AsFpuRegister<SRegister>(),
2320 first.AsFpuRegister<SRegister>(),
2321 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002322 break;
2323
2324 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002325 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2326 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2327 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002328 break;
2329
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002330 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002331 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002332 }
2333}
2334
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002335void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002336 LocationSummary* locations =
2337 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002338 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002339 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002340 locations->SetInAt(0, Location::RequiresRegister());
2341 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002342 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2343 break;
2344 }
2345
2346 case Primitive::kPrimLong: {
2347 locations->SetInAt(0, Location::RequiresRegister());
2348 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002349 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002350 break;
2351 }
Calin Juravle11351682014-10-23 15:38:15 +01002352 case Primitive::kPrimFloat:
2353 case Primitive::kPrimDouble: {
2354 locations->SetInAt(0, Location::RequiresFpuRegister());
2355 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002356 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002357 break;
Calin Juravle11351682014-10-23 15:38:15 +01002358 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002359 default:
Calin Juravle11351682014-10-23 15:38:15 +01002360 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002361 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002362}
2363
2364void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2365 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002366 Location out = locations->Out();
2367 Location first = locations->InAt(0);
2368 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002369 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002370 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002371 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002372 __ sub(out.AsRegister<Register>(),
2373 first.AsRegister<Register>(),
2374 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002375 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002376 __ AddConstant(out.AsRegister<Register>(),
2377 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002378 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002379 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002380 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002381 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002382
Calin Juravle11351682014-10-23 15:38:15 +01002383 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002384 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002385 __ subs(out.AsRegisterPairLow<Register>(),
2386 first.AsRegisterPairLow<Register>(),
2387 ShifterOperand(second.AsRegisterPairLow<Register>()));
2388 __ sbc(out.AsRegisterPairHigh<Register>(),
2389 first.AsRegisterPairHigh<Register>(),
2390 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002391 break;
Calin Juravle11351682014-10-23 15:38:15 +01002392 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002393
Calin Juravle11351682014-10-23 15:38:15 +01002394 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002395 __ vsubs(out.AsFpuRegister<SRegister>(),
2396 first.AsFpuRegister<SRegister>(),
2397 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002398 break;
Calin Juravle11351682014-10-23 15:38:15 +01002399 }
2400
2401 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002402 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2403 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2404 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002405 break;
2406 }
2407
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002408
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002409 default:
Calin Juravle11351682014-10-23 15:38:15 +01002410 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002411 }
2412}
2413
Calin Juravle34bacdf2014-10-07 20:23:36 +01002414void LocationsBuilderARM::VisitMul(HMul* mul) {
2415 LocationSummary* locations =
2416 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2417 switch (mul->GetResultType()) {
2418 case Primitive::kPrimInt:
2419 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002420 locations->SetInAt(0, Location::RequiresRegister());
2421 locations->SetInAt(1, Location::RequiresRegister());
2422 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002423 break;
2424 }
2425
Calin Juravleb5bfa962014-10-21 18:02:24 +01002426 case Primitive::kPrimFloat:
2427 case Primitive::kPrimDouble: {
2428 locations->SetInAt(0, Location::RequiresFpuRegister());
2429 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002430 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002431 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002432 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002433
2434 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002435 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002436 }
2437}
2438
2439void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2440 LocationSummary* locations = mul->GetLocations();
2441 Location out = locations->Out();
2442 Location first = locations->InAt(0);
2443 Location second = locations->InAt(1);
2444 switch (mul->GetResultType()) {
2445 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002446 __ mul(out.AsRegister<Register>(),
2447 first.AsRegister<Register>(),
2448 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002449 break;
2450 }
2451 case Primitive::kPrimLong: {
2452 Register out_hi = out.AsRegisterPairHigh<Register>();
2453 Register out_lo = out.AsRegisterPairLow<Register>();
2454 Register in1_hi = first.AsRegisterPairHigh<Register>();
2455 Register in1_lo = first.AsRegisterPairLow<Register>();
2456 Register in2_hi = second.AsRegisterPairHigh<Register>();
2457 Register in2_lo = second.AsRegisterPairLow<Register>();
2458
2459 // Extra checks to protect caused by the existence of R1_R2.
2460 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2461 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2462 DCHECK_NE(out_hi, in1_lo);
2463 DCHECK_NE(out_hi, in2_lo);
2464
2465 // input: in1 - 64 bits, in2 - 64 bits
2466 // output: out
2467 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2468 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2469 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2470
2471 // IP <- in1.lo * in2.hi
2472 __ mul(IP, in1_lo, in2_hi);
2473 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2474 __ mla(out_hi, in1_hi, in2_lo, IP);
2475 // out.lo <- (in1.lo * in2.lo)[31:0];
2476 __ umull(out_lo, IP, in1_lo, in2_lo);
2477 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2478 __ add(out_hi, out_hi, ShifterOperand(IP));
2479 break;
2480 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002481
2482 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002483 __ vmuls(out.AsFpuRegister<SRegister>(),
2484 first.AsFpuRegister<SRegister>(),
2485 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002486 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002487 }
2488
2489 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002490 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2491 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2492 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002493 break;
2494 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002495
2496 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002497 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002498 }
2499}
2500
Zheng Xuc6667102015-05-15 16:08:45 +08002501void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2502 DCHECK(instruction->IsDiv() || instruction->IsRem());
2503 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2504
2505 LocationSummary* locations = instruction->GetLocations();
2506 Location second = locations->InAt(1);
2507 DCHECK(second.IsConstant());
2508
2509 Register out = locations->Out().AsRegister<Register>();
2510 Register dividend = locations->InAt(0).AsRegister<Register>();
2511 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2512 DCHECK(imm == 1 || imm == -1);
2513
2514 if (instruction->IsRem()) {
2515 __ LoadImmediate(out, 0);
2516 } else {
2517 if (imm == 1) {
2518 __ Mov(out, dividend);
2519 } else {
2520 __ rsb(out, dividend, ShifterOperand(0));
2521 }
2522 }
2523}
2524
2525void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2526 DCHECK(instruction->IsDiv() || instruction->IsRem());
2527 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2528
2529 LocationSummary* locations = instruction->GetLocations();
2530 Location second = locations->InAt(1);
2531 DCHECK(second.IsConstant());
2532
2533 Register out = locations->Out().AsRegister<Register>();
2534 Register dividend = locations->InAt(0).AsRegister<Register>();
2535 Register temp = locations->GetTemp(0).AsRegister<Register>();
2536 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Vladimir Marko80afd022015-05-19 18:08:00 +01002537 uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002538 DCHECK(IsPowerOfTwo(abs_imm));
2539 int ctz_imm = CTZ(abs_imm);
2540
2541 if (ctz_imm == 1) {
2542 __ Lsr(temp, dividend, 32 - ctz_imm);
2543 } else {
2544 __ Asr(temp, dividend, 31);
2545 __ Lsr(temp, temp, 32 - ctz_imm);
2546 }
2547 __ add(out, temp, ShifterOperand(dividend));
2548
2549 if (instruction->IsDiv()) {
2550 __ Asr(out, out, ctz_imm);
2551 if (imm < 0) {
2552 __ rsb(out, out, ShifterOperand(0));
2553 }
2554 } else {
2555 __ ubfx(out, out, 0, ctz_imm);
2556 __ sub(out, out, ShifterOperand(temp));
2557 }
2558}
2559
2560void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2561 DCHECK(instruction->IsDiv() || instruction->IsRem());
2562 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2563
2564 LocationSummary* locations = instruction->GetLocations();
2565 Location second = locations->InAt(1);
2566 DCHECK(second.IsConstant());
2567
2568 Register out = locations->Out().AsRegister<Register>();
2569 Register dividend = locations->InAt(0).AsRegister<Register>();
2570 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2571 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2572 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2573
2574 int64_t magic;
2575 int shift;
2576 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2577
2578 __ LoadImmediate(temp1, magic);
2579 __ smull(temp2, temp1, dividend, temp1);
2580
2581 if (imm > 0 && magic < 0) {
2582 __ add(temp1, temp1, ShifterOperand(dividend));
2583 } else if (imm < 0 && magic > 0) {
2584 __ sub(temp1, temp1, ShifterOperand(dividend));
2585 }
2586
2587 if (shift != 0) {
2588 __ Asr(temp1, temp1, shift);
2589 }
2590
2591 if (instruction->IsDiv()) {
2592 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2593 } else {
2594 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2595 // TODO: Strength reduction for mls.
2596 __ LoadImmediate(temp2, imm);
2597 __ mls(out, temp1, temp2, dividend);
2598 }
2599}
2600
2601void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2602 DCHECK(instruction->IsDiv() || instruction->IsRem());
2603 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2604
2605 LocationSummary* locations = instruction->GetLocations();
2606 Location second = locations->InAt(1);
2607 DCHECK(second.IsConstant());
2608
2609 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2610 if (imm == 0) {
2611 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2612 } else if (imm == 1 || imm == -1) {
2613 DivRemOneOrMinusOne(instruction);
2614 } else if (IsPowerOfTwo(std::abs(imm))) {
2615 DivRemByPowerOfTwo(instruction);
2616 } else {
2617 DCHECK(imm <= -2 || imm >= 2);
2618 GenerateDivRemWithAnyConstant(instruction);
2619 }
2620}
2621
Calin Juravle7c4954d2014-10-28 16:57:40 +00002622void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002623 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2624 if (div->GetResultType() == Primitive::kPrimLong) {
2625 // pLdiv runtime call.
2626 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002627 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2628 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002629 } else if (div->GetResultType() == Primitive::kPrimInt &&
2630 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2631 // pIdivmod runtime call.
2632 call_kind = LocationSummary::kCall;
2633 }
2634
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002635 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2636
Calin Juravle7c4954d2014-10-28 16:57:40 +00002637 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002638 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002639 if (div->InputAt(1)->IsConstant()) {
2640 locations->SetInAt(0, Location::RequiresRegister());
2641 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
2642 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2643 int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2644 if (abs_imm <= 1) {
2645 // No temp register required.
2646 } else {
2647 locations->AddTemp(Location::RequiresRegister());
2648 if (!IsPowerOfTwo(abs_imm)) {
2649 locations->AddTemp(Location::RequiresRegister());
2650 }
2651 }
2652 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002653 locations->SetInAt(0, Location::RequiresRegister());
2654 locations->SetInAt(1, Location::RequiresRegister());
2655 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2656 } else {
2657 InvokeRuntimeCallingConvention calling_convention;
2658 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2659 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2660 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2661 // we only need the former.
2662 locations->SetOut(Location::RegisterLocation(R0));
2663 }
Calin Juravled0d48522014-11-04 16:40:20 +00002664 break;
2665 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002666 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002667 InvokeRuntimeCallingConvention calling_convention;
2668 locations->SetInAt(0, Location::RegisterPairLocation(
2669 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2670 locations->SetInAt(1, Location::RegisterPairLocation(
2671 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002672 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002673 break;
2674 }
2675 case Primitive::kPrimFloat:
2676 case Primitive::kPrimDouble: {
2677 locations->SetInAt(0, Location::RequiresFpuRegister());
2678 locations->SetInAt(1, Location::RequiresFpuRegister());
2679 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2680 break;
2681 }
2682
2683 default:
2684 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2685 }
2686}
2687
2688void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2689 LocationSummary* locations = div->GetLocations();
2690 Location out = locations->Out();
2691 Location first = locations->InAt(0);
2692 Location second = locations->InAt(1);
2693
2694 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002695 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002696 if (second.IsConstant()) {
2697 GenerateDivRemConstantIntegral(div);
2698 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002699 __ sdiv(out.AsRegister<Register>(),
2700 first.AsRegister<Register>(),
2701 second.AsRegister<Register>());
2702 } else {
2703 InvokeRuntimeCallingConvention calling_convention;
2704 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2705 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2706 DCHECK_EQ(R0, out.AsRegister<Register>());
2707
2708 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2709 }
Calin Juravled0d48522014-11-04 16:40:20 +00002710 break;
2711 }
2712
Calin Juravle7c4954d2014-10-28 16:57:40 +00002713 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002714 InvokeRuntimeCallingConvention calling_convention;
2715 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2716 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2717 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2718 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2719 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002720 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002721
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002722 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002723 break;
2724 }
2725
2726 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002727 __ vdivs(out.AsFpuRegister<SRegister>(),
2728 first.AsFpuRegister<SRegister>(),
2729 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002730 break;
2731 }
2732
2733 case Primitive::kPrimDouble: {
2734 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2735 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2736 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2737 break;
2738 }
2739
2740 default:
2741 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2742 }
2743}
2744
Calin Juravlebacfec32014-11-14 15:54:36 +00002745void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002746 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002747
2748 // Most remainders are implemented in the runtime.
2749 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002750 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
2751 // sdiv will be replaced by other instruction sequence.
2752 call_kind = LocationSummary::kNoCall;
2753 } else if ((rem->GetResultType() == Primitive::kPrimInt)
2754 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002755 // Have hardware divide instruction for int, do it with three instructions.
2756 call_kind = LocationSummary::kNoCall;
2757 }
2758
Calin Juravlebacfec32014-11-14 15:54:36 +00002759 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2760
Calin Juravled2ec87d2014-12-08 14:24:46 +00002761 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002762 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002763 if (rem->InputAt(1)->IsConstant()) {
2764 locations->SetInAt(0, Location::RequiresRegister());
2765 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
2766 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2767 int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
2768 if (abs_imm <= 1) {
2769 // No temp register required.
2770 } else {
2771 locations->AddTemp(Location::RequiresRegister());
2772 if (!IsPowerOfTwo(abs_imm)) {
2773 locations->AddTemp(Location::RequiresRegister());
2774 }
2775 }
2776 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002777 locations->SetInAt(0, Location::RequiresRegister());
2778 locations->SetInAt(1, Location::RequiresRegister());
2779 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2780 locations->AddTemp(Location::RequiresRegister());
2781 } else {
2782 InvokeRuntimeCallingConvention calling_convention;
2783 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2784 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2785 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2786 // we only need the latter.
2787 locations->SetOut(Location::RegisterLocation(R1));
2788 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002789 break;
2790 }
2791 case Primitive::kPrimLong: {
2792 InvokeRuntimeCallingConvention calling_convention;
2793 locations->SetInAt(0, Location::RegisterPairLocation(
2794 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2795 locations->SetInAt(1, Location::RegisterPairLocation(
2796 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2797 // The runtime helper puts the output in R2,R3.
2798 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2799 break;
2800 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002801 case Primitive::kPrimFloat: {
2802 InvokeRuntimeCallingConvention calling_convention;
2803 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2804 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2805 locations->SetOut(Location::FpuRegisterLocation(S0));
2806 break;
2807 }
2808
Calin Juravlebacfec32014-11-14 15:54:36 +00002809 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002810 InvokeRuntimeCallingConvention calling_convention;
2811 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2812 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2813 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2814 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2815 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002816 break;
2817 }
2818
2819 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002820 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002821 }
2822}
2823
2824void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2825 LocationSummary* locations = rem->GetLocations();
2826 Location out = locations->Out();
2827 Location first = locations->InAt(0);
2828 Location second = locations->InAt(1);
2829
Calin Juravled2ec87d2014-12-08 14:24:46 +00002830 Primitive::Type type = rem->GetResultType();
2831 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002832 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002833 if (second.IsConstant()) {
2834 GenerateDivRemConstantIntegral(rem);
2835 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002836 Register reg1 = first.AsRegister<Register>();
2837 Register reg2 = second.AsRegister<Register>();
2838 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002839
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002840 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002841 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002842 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002843 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002844 } else {
2845 InvokeRuntimeCallingConvention calling_convention;
2846 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2847 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2848 DCHECK_EQ(R1, out.AsRegister<Register>());
2849
2850 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2851 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002852 break;
2853 }
2854
2855 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002856 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002857 break;
2858 }
2859
Calin Juravled2ec87d2014-12-08 14:24:46 +00002860 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002861 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002862 break;
2863 }
2864
Calin Juravlebacfec32014-11-14 15:54:36 +00002865 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002866 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002867 break;
2868 }
2869
2870 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002871 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002872 }
2873}
2874
Calin Juravled0d48522014-11-04 16:40:20 +00002875void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00002876 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
2877 ? LocationSummary::kCallOnSlowPath
2878 : LocationSummary::kNoCall;
2879 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002880 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002881 if (instruction->HasUses()) {
2882 locations->SetOut(Location::SameAsFirstInput());
2883 }
2884}
2885
2886void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07002887 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00002888 codegen_->AddSlowPath(slow_path);
2889
2890 LocationSummary* locations = instruction->GetLocations();
2891 Location value = locations->InAt(0);
2892
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002893 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06002894 case Primitive::kPrimByte:
2895 case Primitive::kPrimChar:
2896 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002897 case Primitive::kPrimInt: {
2898 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01002899 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002900 } else {
2901 DCHECK(value.IsConstant()) << value;
2902 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2903 __ b(slow_path->GetEntryLabel());
2904 }
2905 }
2906 break;
2907 }
2908 case Primitive::kPrimLong: {
2909 if (value.IsRegisterPair()) {
2910 __ orrs(IP,
2911 value.AsRegisterPairLow<Register>(),
2912 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2913 __ b(slow_path->GetEntryLabel(), EQ);
2914 } else {
2915 DCHECK(value.IsConstant()) << value;
2916 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2917 __ b(slow_path->GetEntryLabel());
2918 }
2919 }
2920 break;
2921 default:
2922 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2923 }
2924 }
Calin Juravled0d48522014-11-04 16:40:20 +00002925}
2926
Calin Juravle9aec02f2014-11-18 23:06:35 +00002927void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2928 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2929
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002930 LocationSummary* locations =
2931 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002932
2933 switch (op->GetResultType()) {
2934 case Primitive::kPrimInt: {
2935 locations->SetInAt(0, Location::RequiresRegister());
2936 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002937 // Make the output overlap, as it will be used to hold the masked
2938 // second input.
2939 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002940 break;
2941 }
2942 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002943 locations->SetInAt(0, Location::RequiresRegister());
2944 locations->SetInAt(1, Location::RequiresRegister());
2945 locations->AddTemp(Location::RequiresRegister());
2946 locations->SetOut(Location::RequiresRegister());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002947 break;
2948 }
2949 default:
2950 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2951 }
2952}
2953
2954void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2955 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2956
2957 LocationSummary* locations = op->GetLocations();
2958 Location out = locations->Out();
2959 Location first = locations->InAt(0);
2960 Location second = locations->InAt(1);
2961
2962 Primitive::Type type = op->GetResultType();
2963 switch (type) {
2964 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002965 Register out_reg = out.AsRegister<Register>();
2966 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002967 // Arm doesn't mask the shift count so we need to do it ourselves.
2968 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002969 Register second_reg = second.AsRegister<Register>();
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002970 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
Calin Juravle9aec02f2014-11-18 23:06:35 +00002971 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002972 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002973 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002974 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002975 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002976 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002977 }
2978 } else {
2979 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2980 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2981 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2982 __ Mov(out_reg, first_reg);
2983 } else if (op->IsShl()) {
2984 __ Lsl(out_reg, first_reg, shift_value);
2985 } else if (op->IsShr()) {
2986 __ Asr(out_reg, first_reg, shift_value);
2987 } else {
2988 __ Lsr(out_reg, first_reg, shift_value);
2989 }
2990 }
2991 break;
2992 }
2993 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002994 Register o_h = out.AsRegisterPairHigh<Register>();
2995 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002996
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002997 Register temp = locations->GetTemp(0).AsRegister<Register>();
2998
2999 Register high = first.AsRegisterPairHigh<Register>();
3000 Register low = first.AsRegisterPairLow<Register>();
3001
3002 Register second_reg = second.AsRegister<Register>();
3003
Calin Juravle9aec02f2014-11-18 23:06:35 +00003004 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003005 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003006 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003007 __ Lsl(o_h, high, o_l);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003008 // Shift the low part and `or` what overflew on the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003009 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003010 __ Lsr(temp, low, temp);
3011 __ orr(o_h, o_h, ShifterOperand(temp));
3012 // If the shift is > 32 bits, override the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003013 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003014 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003015 __ Lsl(o_h, low, temp, PL);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003016 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003017 __ Lsl(o_l, low, o_l);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003018 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003019 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003020 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003021 __ Lsr(o_l, low, o_h);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003022 // Shift the high part and `or` what underflew on the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003023 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003024 __ Lsl(temp, high, temp);
3025 __ orr(o_l, o_l, ShifterOperand(temp));
3026 // If the shift is > 32 bits, override the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003027 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003028 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003029 __ Asr(o_l, high, temp, PL);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003030 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003031 __ Asr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003032 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003033 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003034 // same as Shr except we use `Lsr`s and not `Asr`s
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003035 __ Lsr(o_l, low, o_h);
3036 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003037 __ Lsl(temp, high, temp);
3038 __ orr(o_l, o_l, ShifterOperand(temp));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003039 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003040 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01003041 __ Lsr(o_l, high, temp, PL);
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003042 __ Lsr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003043 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003044 break;
3045 }
3046 default:
3047 LOG(FATAL) << "Unexpected operation type " << type;
3048 }
3049}
3050
3051void LocationsBuilderARM::VisitShl(HShl* shl) {
3052 HandleShift(shl);
3053}
3054
3055void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3056 HandleShift(shl);
3057}
3058
3059void LocationsBuilderARM::VisitShr(HShr* shr) {
3060 HandleShift(shr);
3061}
3062
3063void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3064 HandleShift(shr);
3065}
3066
3067void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3068 HandleShift(ushr);
3069}
3070
3071void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3072 HandleShift(ushr);
3073}
3074
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003075void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003076 LocationSummary* locations =
3077 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003078 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003079 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003080 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003081 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003082}
3083
3084void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
3085 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003086 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003087 // Note: if heap poisoning is enabled, the entry point takes cares
3088 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003089 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003090 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003091 instruction->GetDexPc(),
3092 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003093}
3094
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003095void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3096 LocationSummary* locations =
3097 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3098 InvokeRuntimeCallingConvention calling_convention;
3099 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003100 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003101 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003102 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003103}
3104
3105void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3106 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003107 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003108 // Note: if heap poisoning is enabled, the entry point takes cares
3109 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003110 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003111 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003112 instruction->GetDexPc(),
3113 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003114}
3115
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003116void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003117 LocationSummary* locations =
3118 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003119 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3120 if (location.IsStackSlot()) {
3121 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3122 } else if (location.IsDoubleStackSlot()) {
3123 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003124 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003125 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003126}
3127
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003128void InstructionCodeGeneratorARM::VisitParameterValue(
3129 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003130 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003131}
3132
3133void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3134 LocationSummary* locations =
3135 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3136 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3137}
3138
3139void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3140 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003141}
3142
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003143void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003144 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003145 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003146 locations->SetInAt(0, Location::RequiresRegister());
3147 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003148}
3149
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003150void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3151 LocationSummary* locations = not_->GetLocations();
3152 Location out = locations->Out();
3153 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003154 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003155 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003156 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003157 break;
3158
3159 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003160 __ mvn(out.AsRegisterPairLow<Register>(),
3161 ShifterOperand(in.AsRegisterPairLow<Register>()));
3162 __ mvn(out.AsRegisterPairHigh<Register>(),
3163 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003164 break;
3165
3166 default:
3167 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3168 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003169}
3170
David Brazdil66d126e2015-04-03 16:02:44 +01003171void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3172 LocationSummary* locations =
3173 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3174 locations->SetInAt(0, Location::RequiresRegister());
3175 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3176}
3177
3178void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003179 LocationSummary* locations = bool_not->GetLocations();
3180 Location out = locations->Out();
3181 Location in = locations->InAt(0);
3182 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3183}
3184
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003185void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003186 LocationSummary* locations =
3187 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003188 switch (compare->InputAt(0)->GetType()) {
3189 case Primitive::kPrimLong: {
3190 locations->SetInAt(0, Location::RequiresRegister());
3191 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003192 // Output overlaps because it is written before doing the low comparison.
3193 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003194 break;
3195 }
3196 case Primitive::kPrimFloat:
3197 case Primitive::kPrimDouble: {
3198 locations->SetInAt(0, Location::RequiresFpuRegister());
3199 locations->SetInAt(1, Location::RequiresFpuRegister());
3200 locations->SetOut(Location::RequiresRegister());
3201 break;
3202 }
3203 default:
3204 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3205 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003206}
3207
3208void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003209 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003210 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003211 Location left = locations->InAt(0);
3212 Location right = locations->InAt(1);
3213
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003214 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003215 Primitive::Type type = compare->InputAt(0)->GetType();
3216 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003217 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003218 __ cmp(left.AsRegisterPairHigh<Register>(),
3219 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003220 __ b(&less, LT);
3221 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003222 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003223 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003224 __ cmp(left.AsRegisterPairLow<Register>(),
3225 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00003226 break;
3227 }
3228 case Primitive::kPrimFloat:
3229 case Primitive::kPrimDouble: {
3230 __ LoadImmediate(out, 0);
3231 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003232 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003233 } else {
3234 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3235 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3236 }
3237 __ vmstat(); // transfer FP status register to ARM APSR.
3238 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003239 break;
3240 }
3241 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003242 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003243 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003244 __ b(&done, EQ);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003245 __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats.
Calin Juravleddb7df22014-11-25 20:56:51 +00003246
3247 __ Bind(&greater);
3248 __ LoadImmediate(out, 1);
3249 __ b(&done);
3250
3251 __ Bind(&less);
3252 __ LoadImmediate(out, -1);
3253
3254 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003255}
3256
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003257void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003258 LocationSummary* locations =
3259 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003260 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3261 locations->SetInAt(i, Location::Any());
3262 }
3263 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003264}
3265
3266void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003267 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003268 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003269}
3270
Calin Juravle52c48962014-12-16 17:02:57 +00003271void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3272 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07003273 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00003274 switch (kind) {
3275 case MemBarrierKind::kAnyStore:
3276 case MemBarrierKind::kLoadAny:
3277 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003278 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003279 break;
3280 }
3281 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003282 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003283 break;
3284 }
3285 default:
3286 LOG(FATAL) << "Unexpected memory barrier " << kind;
3287 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003288 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003289}
3290
3291void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3292 uint32_t offset,
3293 Register out_lo,
3294 Register out_hi) {
3295 if (offset != 0) {
3296 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003297 __ add(IP, addr, ShifterOperand(out_lo));
3298 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003299 }
3300 __ ldrexd(out_lo, out_hi, addr);
3301}
3302
3303void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3304 uint32_t offset,
3305 Register value_lo,
3306 Register value_hi,
3307 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003308 Register temp2,
3309 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003310 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003311 if (offset != 0) {
3312 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003313 __ add(IP, addr, ShifterOperand(temp1));
3314 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003315 }
3316 __ Bind(&fail);
3317 // We need a load followed by store. (The address used in a STREX instruction must
3318 // be the same as the address in the most recently executed LDREX instruction.)
3319 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003320 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003321 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003322 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003323}
3324
3325void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3326 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3327
Nicolas Geoffray39468442014-09-02 15:17:15 +01003328 LocationSummary* locations =
3329 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003330 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003331
Calin Juravle52c48962014-12-16 17:02:57 +00003332 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003333 if (Primitive::IsFloatingPointType(field_type)) {
3334 locations->SetInAt(1, Location::RequiresFpuRegister());
3335 } else {
3336 locations->SetInAt(1, Location::RequiresRegister());
3337 }
3338
Calin Juravle52c48962014-12-16 17:02:57 +00003339 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003340 bool generate_volatile = field_info.IsVolatile()
3341 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003342 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003343 bool needs_write_barrier =
3344 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003345 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003346 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003347 if (needs_write_barrier) {
3348 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003349 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003350 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00003351 // Arm encoding have some additional constraints for ldrexd/strexd:
3352 // - registers need to be consecutive
3353 // - the first register should be even but not R14.
3354 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3355 // enable Arm encoding.
3356 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3357
3358 locations->AddTemp(Location::RequiresRegister());
3359 locations->AddTemp(Location::RequiresRegister());
3360 if (field_type == Primitive::kPrimDouble) {
3361 // For doubles we need two more registers to copy the value.
3362 locations->AddTemp(Location::RegisterLocation(R2));
3363 locations->AddTemp(Location::RegisterLocation(R3));
3364 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003365 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003366}
3367
Calin Juravle52c48962014-12-16 17:02:57 +00003368void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003369 const FieldInfo& field_info,
3370 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003371 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3372
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003373 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003374 Register base = locations->InAt(0).AsRegister<Register>();
3375 Location value = locations->InAt(1);
3376
3377 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003378 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003379 Primitive::Type field_type = field_info.GetFieldType();
3380 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003381 bool needs_write_barrier =
3382 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003383
3384 if (is_volatile) {
3385 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3386 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003387
3388 switch (field_type) {
3389 case Primitive::kPrimBoolean:
3390 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003391 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003392 break;
3393 }
3394
3395 case Primitive::kPrimShort:
3396 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003397 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003398 break;
3399 }
3400
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003401 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003402 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003403 if (kPoisonHeapReferences && needs_write_barrier) {
3404 // Note that in the case where `value` is a null reference,
3405 // we do not enter this block, as a null reference does not
3406 // need poisoning.
3407 DCHECK_EQ(field_type, Primitive::kPrimNot);
3408 Register temp = locations->GetTemp(0).AsRegister<Register>();
3409 __ Mov(temp, value.AsRegister<Register>());
3410 __ PoisonHeapReference(temp);
3411 __ StoreToOffset(kStoreWord, temp, base, offset);
3412 } else {
3413 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3414 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003415 break;
3416 }
3417
3418 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003419 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003420 GenerateWideAtomicStore(base, offset,
3421 value.AsRegisterPairLow<Register>(),
3422 value.AsRegisterPairHigh<Register>(),
3423 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003424 locations->GetTemp(1).AsRegister<Register>(),
3425 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003426 } else {
3427 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003428 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003429 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003430 break;
3431 }
3432
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003433 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003434 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003435 break;
3436 }
3437
3438 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003439 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003440 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003441 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3442 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3443
3444 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3445
3446 GenerateWideAtomicStore(base, offset,
3447 value_reg_lo,
3448 value_reg_hi,
3449 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003450 locations->GetTemp(3).AsRegister<Register>(),
3451 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003452 } else {
3453 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003454 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003455 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003456 break;
3457 }
3458
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003459 case Primitive::kPrimVoid:
3460 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003461 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003462 }
Calin Juravle52c48962014-12-16 17:02:57 +00003463
Calin Juravle77520bc2015-01-12 18:45:46 +00003464 // Longs and doubles are handled in the switch.
3465 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3466 codegen_->MaybeRecordImplicitNullCheck(instruction);
3467 }
3468
3469 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3470 Register temp = locations->GetTemp(0).AsRegister<Register>();
3471 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003472 codegen_->MarkGCCard(
3473 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003474 }
3475
Calin Juravle52c48962014-12-16 17:02:57 +00003476 if (is_volatile) {
3477 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3478 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003479}
3480
Calin Juravle52c48962014-12-16 17:02:57 +00003481void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3482 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003483 LocationSummary* locations =
3484 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003485 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003486
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003487 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003488 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003489 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003490 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003491
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003492 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3493 locations->SetOut(Location::RequiresFpuRegister());
3494 } else {
3495 locations->SetOut(Location::RequiresRegister(),
3496 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3497 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003498 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00003499 // Arm encoding have some additional constraints for ldrexd/strexd:
3500 // - registers need to be consecutive
3501 // - the first register should be even but not R14.
3502 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3503 // enable Arm encoding.
3504 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3505 locations->AddTemp(Location::RequiresRegister());
3506 locations->AddTemp(Location::RequiresRegister());
3507 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003508}
3509
Calin Juravle52c48962014-12-16 17:02:57 +00003510void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
3511 const FieldInfo& field_info) {
3512 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003513
Calin Juravle52c48962014-12-16 17:02:57 +00003514 LocationSummary* locations = instruction->GetLocations();
3515 Register base = locations->InAt(0).AsRegister<Register>();
3516 Location out = locations->Out();
3517 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003518 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003519 Primitive::Type field_type = field_info.GetFieldType();
3520 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3521
3522 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003523 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003524 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003525 break;
3526 }
3527
3528 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003529 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003530 break;
3531 }
3532
3533 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003534 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003535 break;
3536 }
3537
3538 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003539 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003540 break;
3541 }
3542
3543 case Primitive::kPrimInt:
3544 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003545 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003546 break;
3547 }
3548
3549 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003550 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003551 GenerateWideAtomicLoad(base, offset,
3552 out.AsRegisterPairLow<Register>(),
3553 out.AsRegisterPairHigh<Register>());
3554 } else {
3555 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3556 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003557 break;
3558 }
3559
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003560 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003561 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003562 break;
3563 }
3564
3565 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003566 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003567 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003568 Register lo = locations->GetTemp(0).AsRegister<Register>();
3569 Register hi = locations->GetTemp(1).AsRegister<Register>();
3570 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003571 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003572 __ vmovdrr(out_reg, lo, hi);
3573 } else {
3574 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003575 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003576 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003577 break;
3578 }
3579
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003580 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003581 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003582 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003583 }
Calin Juravle52c48962014-12-16 17:02:57 +00003584
Calin Juravle77520bc2015-01-12 18:45:46 +00003585 // Doubles are handled in the switch.
3586 if (field_type != Primitive::kPrimDouble) {
3587 codegen_->MaybeRecordImplicitNullCheck(instruction);
3588 }
3589
Calin Juravle52c48962014-12-16 17:02:57 +00003590 if (is_volatile) {
3591 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3592 }
Roland Levillain4d027112015-07-01 15:41:14 +01003593
3594 if (field_type == Primitive::kPrimNot) {
3595 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3596 }
Calin Juravle52c48962014-12-16 17:02:57 +00003597}
3598
3599void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3600 HandleFieldSet(instruction, instruction->GetFieldInfo());
3601}
3602
3603void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003604 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003605}
3606
3607void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3608 HandleFieldGet(instruction, instruction->GetFieldInfo());
3609}
3610
3611void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3612 HandleFieldGet(instruction, instruction->GetFieldInfo());
3613}
3614
3615void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3616 HandleFieldGet(instruction, instruction->GetFieldInfo());
3617}
3618
3619void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3620 HandleFieldGet(instruction, instruction->GetFieldInfo());
3621}
3622
3623void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3624 HandleFieldSet(instruction, instruction->GetFieldInfo());
3625}
3626
3627void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003628 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003629}
3630
Calin Juravlee460d1d2015-09-29 04:52:17 +01003631void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
3632 HUnresolvedInstanceFieldGet* instruction) {
3633 FieldAccessCallingConventionARM calling_convention;
3634 codegen_->CreateUnresolvedFieldLocationSummary(
3635 instruction, instruction->GetFieldType(), calling_convention);
3636}
3637
3638void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
3639 HUnresolvedInstanceFieldGet* instruction) {
3640 FieldAccessCallingConventionARM calling_convention;
3641 codegen_->GenerateUnresolvedFieldAccess(instruction,
3642 instruction->GetFieldType(),
3643 instruction->GetFieldIndex(),
3644 instruction->GetDexPc(),
3645 calling_convention);
3646}
3647
3648void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
3649 HUnresolvedInstanceFieldSet* instruction) {
3650 FieldAccessCallingConventionARM calling_convention;
3651 codegen_->CreateUnresolvedFieldLocationSummary(
3652 instruction, instruction->GetFieldType(), calling_convention);
3653}
3654
3655void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
3656 HUnresolvedInstanceFieldSet* instruction) {
3657 FieldAccessCallingConventionARM calling_convention;
3658 codegen_->GenerateUnresolvedFieldAccess(instruction,
3659 instruction->GetFieldType(),
3660 instruction->GetFieldIndex(),
3661 instruction->GetDexPc(),
3662 calling_convention);
3663}
3664
3665void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
3666 HUnresolvedStaticFieldGet* instruction) {
3667 FieldAccessCallingConventionARM calling_convention;
3668 codegen_->CreateUnresolvedFieldLocationSummary(
3669 instruction, instruction->GetFieldType(), calling_convention);
3670}
3671
3672void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
3673 HUnresolvedStaticFieldGet* instruction) {
3674 FieldAccessCallingConventionARM calling_convention;
3675 codegen_->GenerateUnresolvedFieldAccess(instruction,
3676 instruction->GetFieldType(),
3677 instruction->GetFieldIndex(),
3678 instruction->GetDexPc(),
3679 calling_convention);
3680}
3681
3682void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
3683 HUnresolvedStaticFieldSet* instruction) {
3684 FieldAccessCallingConventionARM calling_convention;
3685 codegen_->CreateUnresolvedFieldLocationSummary(
3686 instruction, instruction->GetFieldType(), calling_convention);
3687}
3688
3689void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
3690 HUnresolvedStaticFieldSet* instruction) {
3691 FieldAccessCallingConventionARM calling_convention;
3692 codegen_->GenerateUnresolvedFieldAccess(instruction,
3693 instruction->GetFieldType(),
3694 instruction->GetFieldIndex(),
3695 instruction->GetDexPc(),
3696 calling_convention);
3697}
3698
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003699void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003700 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3701 ? LocationSummary::kCallOnSlowPath
3702 : LocationSummary::kNoCall;
3703 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00003704 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003705 if (instruction->HasUses()) {
3706 locations->SetOut(Location::SameAsFirstInput());
3707 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003708}
3709
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003710void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003711 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3712 return;
3713 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003714 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003715
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003716 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3717 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3718}
3719
3720void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003721 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003722 codegen_->AddSlowPath(slow_path);
3723
3724 LocationSummary* locations = instruction->GetLocations();
3725 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003726
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003727 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003728}
3729
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003730void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003731 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003732 GenerateImplicitNullCheck(instruction);
3733 } else {
3734 GenerateExplicitNullCheck(instruction);
3735 }
3736}
3737
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003738void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003739 LocationSummary* locations =
3740 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003741 locations->SetInAt(0, Location::RequiresRegister());
3742 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003743 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3744 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3745 } else {
3746 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3747 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003748}
3749
3750void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3751 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003752 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003753 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003754 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003755
Roland Levillain4d027112015-07-01 15:41:14 +01003756 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003757 case Primitive::kPrimBoolean: {
3758 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003759 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003760 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003761 size_t offset =
3762 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003763 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3764 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003765 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003766 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3767 }
3768 break;
3769 }
3770
3771 case Primitive::kPrimByte: {
3772 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003773 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003774 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003775 size_t offset =
3776 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003777 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3778 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003779 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003780 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3781 }
3782 break;
3783 }
3784
3785 case Primitive::kPrimShort: {
3786 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003787 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003788 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003789 size_t offset =
3790 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003791 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3792 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003793 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003794 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3795 }
3796 break;
3797 }
3798
3799 case Primitive::kPrimChar: {
3800 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003801 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003802 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003803 size_t offset =
3804 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003805 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3806 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003807 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003808 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3809 }
3810 break;
3811 }
3812
3813 case Primitive::kPrimInt:
3814 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003815 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3816 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003817 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003818 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003819 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003820 size_t offset =
3821 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003822 __ LoadFromOffset(kLoadWord, out, obj, offset);
3823 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003824 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003825 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3826 }
3827 break;
3828 }
3829
3830 case Primitive::kPrimLong: {
3831 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003832 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003833 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003834 size_t offset =
3835 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003836 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003837 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003838 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003839 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003840 }
3841 break;
3842 }
3843
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003844 case Primitive::kPrimFloat: {
3845 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3846 Location out = locations->Out();
3847 DCHECK(out.IsFpuRegister());
3848 if (index.IsConstant()) {
3849 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3850 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3851 } else {
3852 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3853 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3854 }
3855 break;
3856 }
3857
3858 case Primitive::kPrimDouble: {
3859 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3860 Location out = locations->Out();
3861 DCHECK(out.IsFpuRegisterPair());
3862 if (index.IsConstant()) {
3863 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3864 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3865 } else {
3866 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3867 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3868 }
3869 break;
3870 }
3871
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003872 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003873 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003874 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003875 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003876 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003877
3878 if (type == Primitive::kPrimNot) {
3879 Register out = locations->Out().AsRegister<Register>();
3880 __ MaybeUnpoisonHeapReference(out);
3881 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003882}
3883
3884void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003885 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003886
3887 bool needs_write_barrier =
3888 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003889 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003890
Nicolas Geoffray39468442014-09-02 15:17:15 +01003891 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003892 instruction,
3893 may_need_runtime_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
3894 locations->SetInAt(0, Location::RequiresRegister());
3895 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3896 if (Primitive::IsFloatingPointType(value_type)) {
3897 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003898 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003899 locations->SetInAt(2, Location::RequiresRegister());
3900 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003901
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003902 if (needs_write_barrier) {
3903 // Temporary registers for the write barrier.
3904 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
3905 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003906 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003907}
3908
3909void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3910 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003911 Register array = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003912 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003913 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003914 bool may_need_runtime_call = locations->CanCall();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003915 bool needs_write_barrier =
3916 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003917
3918 switch (value_type) {
3919 case Primitive::kPrimBoolean:
3920 case Primitive::kPrimByte: {
3921 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003922 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003923 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003924 size_t offset =
3925 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003926 __ StoreToOffset(kStoreByte, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003927 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003928 __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003929 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3930 }
3931 break;
3932 }
3933
3934 case Primitive::kPrimShort:
3935 case Primitive::kPrimChar: {
3936 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003937 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003938 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003939 size_t offset =
3940 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003941 __ StoreToOffset(kStoreHalfword, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003942 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003943 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003944 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3945 }
3946 break;
3947 }
3948
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003949 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003950 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3951 Register value = locations->InAt(2).AsRegister<Register>();
3952 Register source = value;
3953
3954 if (instruction->InputAt(2)->IsNullConstant()) {
3955 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003956 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003957 size_t offset =
3958 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003959 __ StoreToOffset(kStoreWord, source, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003960 } else {
3961 DCHECK(index.IsRegister()) << index;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003962 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01003963 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003964 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003965 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003966 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01003967
3968 DCHECK(needs_write_barrier);
3969 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
3970 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
3971 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3972 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
3973 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
3974 Label done;
3975 SlowPathCode* slow_path = nullptr;
3976
3977 if (may_need_runtime_call) {
3978 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
3979 codegen_->AddSlowPath(slow_path);
3980 if (instruction->GetValueCanBeNull()) {
3981 Label non_zero;
3982 __ CompareAndBranchIfNonZero(value, &non_zero);
3983 if (index.IsConstant()) {
3984 size_t offset =
3985 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3986 __ StoreToOffset(kStoreWord, value, array, offset);
3987 } else {
3988 DCHECK(index.IsRegister()) << index;
3989 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3990 __ StoreToOffset(kStoreWord, value, IP, data_offset);
3991 }
3992 codegen_->MaybeRecordImplicitNullCheck(instruction);
3993 __ b(&done);
3994 __ Bind(&non_zero);
3995 }
3996
3997 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
3998 codegen_->MaybeRecordImplicitNullCheck(instruction);
3999 __ MaybeUnpoisonHeapReference(temp1);
4000 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4001 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4002 // No need to poison/unpoison, we're comparing two poisoined references.
4003 __ cmp(temp1, ShifterOperand(temp2));
4004 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4005 Label do_put;
4006 __ b(&do_put, EQ);
4007 __ MaybeUnpoisonHeapReference(temp1);
4008 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4009 // No need to poison/unpoison, we're comparing against null.
4010 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4011 __ Bind(&do_put);
4012 } else {
4013 __ b(slow_path->GetEntryLabel(), NE);
4014 }
4015 }
4016
4017 if (kPoisonHeapReferences) {
4018 // Note that in the case where `value` is a null reference,
4019 // we do not enter this block, as a null reference does not
4020 // need poisoning.
4021 DCHECK_EQ(value_type, Primitive::kPrimNot);
4022 __ Mov(temp1, value);
4023 __ PoisonHeapReference(temp1);
4024 source = temp1;
4025 }
4026
4027 if (index.IsConstant()) {
4028 size_t offset =
4029 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4030 __ StoreToOffset(kStoreWord, source, array, offset);
4031 } else {
4032 DCHECK(index.IsRegister()) << index;
4033 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4034 __ StoreToOffset(kStoreWord, source, IP, data_offset);
4035 }
4036
4037 if (!may_need_runtime_call) {
4038 codegen_->MaybeRecordImplicitNullCheck(instruction);
4039 }
4040
4041 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4042
4043 if (done.IsLinked()) {
4044 __ Bind(&done);
4045 }
4046
4047 if (slow_path != nullptr) {
4048 __ Bind(slow_path->GetExitLabel());
4049 }
4050
4051 break;
4052 }
4053
4054 case Primitive::kPrimInt: {
4055 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4056 Register value = locations->InAt(2).AsRegister<Register>();
4057 if (index.IsConstant()) {
4058 size_t offset =
4059 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4060 __ StoreToOffset(kStoreWord, value, array, offset);
4061 } else {
4062 DCHECK(index.IsRegister()) << index;
4063 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4064 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4065 }
4066
4067 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004068 break;
4069 }
4070
4071 case Primitive::kPrimLong: {
4072 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004073 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004074 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004075 size_t offset =
4076 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004077 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004078 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004079 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004080 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004081 }
4082 break;
4083 }
4084
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004085 case Primitive::kPrimFloat: {
4086 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4087 Location value = locations->InAt(2);
4088 DCHECK(value.IsFpuRegister());
4089 if (index.IsConstant()) {
4090 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004091 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004092 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004093 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004094 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4095 }
4096 break;
4097 }
4098
4099 case Primitive::kPrimDouble: {
4100 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4101 Location value = locations->InAt(2);
4102 DCHECK(value.IsFpuRegisterPair());
4103 if (index.IsConstant()) {
4104 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004105 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004106 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004107 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004108 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4109 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004110
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004111 break;
4112 }
4113
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004114 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004115 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004116 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004117 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004118
4119 // Ints and objects are handled in the switch.
4120 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
4121 codegen_->MaybeRecordImplicitNullCheck(instruction);
4122 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004123}
4124
4125void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004126 LocationSummary* locations =
4127 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004128 locations->SetInAt(0, Location::RequiresRegister());
4129 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004130}
4131
4132void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4133 LocationSummary* locations = instruction->GetLocations();
4134 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004135 Register obj = locations->InAt(0).AsRegister<Register>();
4136 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004137 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004138 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004139}
4140
4141void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004142 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4143 ? LocationSummary::kCallOnSlowPath
4144 : LocationSummary::kNoCall;
4145 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004146 locations->SetInAt(0, Location::RequiresRegister());
4147 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004148 if (instruction->HasUses()) {
4149 locations->SetOut(Location::SameAsFirstInput());
4150 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004151}
4152
4153void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4154 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004155 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004156 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004157 codegen_->AddSlowPath(slow_path);
4158
Roland Levillain271ab9c2014-11-27 15:23:57 +00004159 Register index = locations->InAt(0).AsRegister<Register>();
4160 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004161
4162 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004163 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004164}
4165
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004166void CodeGeneratorARM::MarkGCCard(Register temp,
4167 Register card,
4168 Register object,
4169 Register value,
4170 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004171 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004172 if (can_be_null) {
4173 __ CompareAndBranchIfZero(value, &is_null);
4174 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004175 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4176 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4177 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004178 if (can_be_null) {
4179 __ Bind(&is_null);
4180 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004181}
4182
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004183void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
4184 temp->SetLocations(nullptr);
4185}
4186
4187void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
4188 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004189 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004190}
4191
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004192void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004193 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004194 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004195}
4196
4197void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004198 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4199}
4200
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004201void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4202 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4203}
4204
4205void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004206 HBasicBlock* block = instruction->GetBlock();
4207 if (block->GetLoopInformation() != nullptr) {
4208 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4209 // The back edge will generate the suspend check.
4210 return;
4211 }
4212 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4213 // The goto will generate the suspend check.
4214 return;
4215 }
4216 GenerateSuspendCheck(instruction, nullptr);
4217}
4218
4219void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4220 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004221 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004222 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4223 if (slow_path == nullptr) {
4224 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4225 instruction->SetSlowPath(slow_path);
4226 codegen_->AddSlowPath(slow_path);
4227 if (successor != nullptr) {
4228 DCHECK(successor->IsLoopHeader());
4229 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4230 }
4231 } else {
4232 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4233 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004234
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004235 __ LoadFromOffset(
4236 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004237 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004238 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004239 __ Bind(slow_path->GetReturnLabel());
4240 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004241 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004242 __ b(slow_path->GetEntryLabel());
4243 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004244}
4245
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004246ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4247 return codegen_->GetAssembler();
4248}
4249
4250void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004251 DCHECK_LT(index, moves_.size());
4252 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004253 Location source = move->GetSource();
4254 Location destination = move->GetDestination();
4255
4256 if (source.IsRegister()) {
4257 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004258 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004259 } else {
4260 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004261 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004262 SP, destination.GetStackIndex());
4263 }
4264 } else if (source.IsStackSlot()) {
4265 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004266 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004267 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004268 } else if (destination.IsFpuRegister()) {
4269 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004270 } else {
4271 DCHECK(destination.IsStackSlot());
4272 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4273 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4274 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004275 } else if (source.IsFpuRegister()) {
4276 if (destination.IsFpuRegister()) {
4277 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004278 } else {
4279 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004280 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4281 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004282 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004283 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004284 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4285 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004286 } else if (destination.IsRegisterPair()) {
4287 DCHECK(ExpectedPairLayout(destination));
4288 __ LoadFromOffset(
4289 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4290 } else {
4291 DCHECK(destination.IsFpuRegisterPair()) << destination;
4292 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4293 SP,
4294 source.GetStackIndex());
4295 }
4296 } else if (source.IsRegisterPair()) {
4297 if (destination.IsRegisterPair()) {
4298 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4299 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4300 } else {
4301 DCHECK(destination.IsDoubleStackSlot()) << destination;
4302 DCHECK(ExpectedPairLayout(source));
4303 __ StoreToOffset(
4304 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4305 }
4306 } else if (source.IsFpuRegisterPair()) {
4307 if (destination.IsFpuRegisterPair()) {
4308 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4309 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4310 } else {
4311 DCHECK(destination.IsDoubleStackSlot()) << destination;
4312 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4313 SP,
4314 destination.GetStackIndex());
4315 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004316 } else {
4317 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004318 HConstant* constant = source.GetConstant();
4319 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4320 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004321 if (destination.IsRegister()) {
4322 __ LoadImmediate(destination.AsRegister<Register>(), value);
4323 } else {
4324 DCHECK(destination.IsStackSlot());
4325 __ LoadImmediate(IP, value);
4326 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4327 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004328 } else if (constant->IsLongConstant()) {
4329 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004330 if (destination.IsRegisterPair()) {
4331 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4332 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004333 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004334 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004335 __ LoadImmediate(IP, Low32Bits(value));
4336 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4337 __ LoadImmediate(IP, High32Bits(value));
4338 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4339 }
4340 } else if (constant->IsDoubleConstant()) {
4341 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004342 if (destination.IsFpuRegisterPair()) {
4343 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004344 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004345 DCHECK(destination.IsDoubleStackSlot()) << destination;
4346 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004347 __ LoadImmediate(IP, Low32Bits(int_value));
4348 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4349 __ LoadImmediate(IP, High32Bits(int_value));
4350 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4351 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004352 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004353 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004354 float value = constant->AsFloatConstant()->GetValue();
4355 if (destination.IsFpuRegister()) {
4356 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4357 } else {
4358 DCHECK(destination.IsStackSlot());
4359 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4360 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4361 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004362 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004363 }
4364}
4365
4366void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4367 __ Mov(IP, reg);
4368 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4369 __ StoreToOffset(kStoreWord, IP, SP, mem);
4370}
4371
4372void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4373 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4374 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4375 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4376 SP, mem1 + stack_offset);
4377 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4378 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4379 SP, mem2 + stack_offset);
4380 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
4381}
4382
4383void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004384 DCHECK_LT(index, moves_.size());
4385 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004386 Location source = move->GetSource();
4387 Location destination = move->GetDestination();
4388
4389 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004390 DCHECK_NE(source.AsRegister<Register>(), IP);
4391 DCHECK_NE(destination.AsRegister<Register>(), IP);
4392 __ Mov(IP, source.AsRegister<Register>());
4393 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
4394 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004395 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004396 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004397 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004398 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004399 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4400 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004401 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004402 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004403 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004404 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004405 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004406 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004407 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004408 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004409 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4410 destination.AsRegisterPairHigh<Register>(),
4411 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004412 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004413 Register low_reg = source.IsRegisterPair()
4414 ? source.AsRegisterPairLow<Register>()
4415 : destination.AsRegisterPairLow<Register>();
4416 int mem = source.IsRegisterPair()
4417 ? destination.GetStackIndex()
4418 : source.GetStackIndex();
4419 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004420 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004421 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004422 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004423 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004424 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
4425 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004426 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004427 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004428 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004429 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
4430 DRegister reg = source.IsFpuRegisterPair()
4431 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
4432 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
4433 int mem = source.IsFpuRegisterPair()
4434 ? destination.GetStackIndex()
4435 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004436 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004437 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004438 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004439 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
4440 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
4441 : destination.AsFpuRegister<SRegister>();
4442 int mem = source.IsFpuRegister()
4443 ? destination.GetStackIndex()
4444 : source.GetStackIndex();
4445
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004446 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004447 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004448 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004449 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004450 Exchange(source.GetStackIndex(), destination.GetStackIndex());
4451 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004452 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004453 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004454 }
4455}
4456
4457void ParallelMoveResolverARM::SpillScratch(int reg) {
4458 __ Push(static_cast<Register>(reg));
4459}
4460
4461void ParallelMoveResolverARM::RestoreScratch(int reg) {
4462 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004463}
4464
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004465void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004466 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4467 ? LocationSummary::kCallOnSlowPath
4468 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004469 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004470 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004471 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004472 locations->SetOut(Location::RequiresRegister());
4473}
4474
4475void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004476 LocationSummary* locations = cls->GetLocations();
4477 Register out = locations->Out().AsRegister<Register>();
4478 Register current_method = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004479 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004480 DCHECK(!cls->CanCallRuntime());
4481 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004482 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004483 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004484 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004485 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004486 __ LoadFromOffset(kLoadWord,
4487 out,
4488 current_method,
Vladimir Marko05792b92015-08-03 11:56:49 +01004489 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004490 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004491 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004492
Andreas Gampe85b62f22015-09-09 13:15:38 -07004493 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004494 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4495 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004496 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004497 if (cls->MustGenerateClinitCheck()) {
4498 GenerateClassInitializationCheck(slow_path, out);
4499 } else {
4500 __ Bind(slow_path->GetExitLabel());
4501 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004502 }
4503}
4504
4505void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
4506 LocationSummary* locations =
4507 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4508 locations->SetInAt(0, Location::RequiresRegister());
4509 if (check->HasUses()) {
4510 locations->SetOut(Location::SameAsFirstInput());
4511 }
4512}
4513
4514void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004515 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07004516 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004517 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004518 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004519 GenerateClassInitializationCheck(slow_path,
4520 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004521}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004522
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004523void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07004524 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004525 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
4526 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
4527 __ b(slow_path->GetEntryLabel(), LT);
4528 // Even if the initialized flag is set, we may be in a situation where caches are not synced
4529 // properly. Therefore, we do a memory fence.
4530 __ dmb(ISH);
4531 __ Bind(slow_path->GetExitLabel());
4532}
4533
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004534void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
4535 LocationSummary* locations =
4536 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004537 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004538 locations->SetOut(Location::RequiresRegister());
4539}
4540
4541void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004542 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004543 codegen_->AddSlowPath(slow_path);
4544
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004545 LocationSummary* locations = load->GetLocations();
4546 Register out = locations->Out().AsRegister<Register>();
4547 Register current_method = locations->InAt(0).AsRegister<Register>();
4548 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004549 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Mathieu Chartiereace4582014-11-24 18:29:54 -08004550 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004551 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004552 // TODO: We will need a read barrier here.
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004553 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004554 __ Bind(slow_path->GetExitLabel());
4555}
4556
David Brazdilcb1c0552015-08-04 16:22:25 +01004557static int32_t GetExceptionTlsOffset() {
4558 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
4559}
4560
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004561void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
4562 LocationSummary* locations =
4563 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4564 locations->SetOut(Location::RequiresRegister());
4565}
4566
4567void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004568 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01004569 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
4570}
4571
4572void LocationsBuilderARM::VisitClearException(HClearException* clear) {
4573 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4574}
4575
4576void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004577 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01004578 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004579}
4580
4581void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
4582 LocationSummary* locations =
4583 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4584 InvokeRuntimeCallingConvention calling_convention;
4585 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4586}
4587
4588void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
4589 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004590 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004591}
4592
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004593void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004594 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4595 switch (instruction->GetTypeCheckKind()) {
4596 case TypeCheckKind::kExactCheck:
4597 case TypeCheckKind::kAbstractClassCheck:
4598 case TypeCheckKind::kClassHierarchyCheck:
4599 case TypeCheckKind::kArrayObjectCheck:
4600 call_kind = LocationSummary::kNoCall;
4601 break;
4602 case TypeCheckKind::kInterfaceCheck:
4603 call_kind = LocationSummary::kCall;
4604 break;
4605 case TypeCheckKind::kArrayCheck:
4606 call_kind = LocationSummary::kCallOnSlowPath;
4607 break;
4608 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004609 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004610 if (call_kind != LocationSummary::kCall) {
4611 locations->SetInAt(0, Location::RequiresRegister());
4612 locations->SetInAt(1, Location::RequiresRegister());
4613 // The out register is used as a temporary, so it overlaps with the inputs.
4614 // Note that TypeCheckSlowPathARM uses this register too.
4615 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4616 } else {
4617 InvokeRuntimeCallingConvention calling_convention;
4618 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4619 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4620 locations->SetOut(Location::RegisterLocation(R0));
4621 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004622}
4623
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004624void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004625 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004626 Register obj = locations->InAt(0).AsRegister<Register>();
4627 Register cls = locations->InAt(1).AsRegister<Register>();
4628 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004629 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004630 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4631 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4632 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004633 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07004634 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004635
4636 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004637 // avoid null check if we know obj is not null.
4638 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00004639 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004640 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004641
4642 // In case of an interface check, we put the object class into the object register.
4643 // This is safe, as the register is caller-save, and the object must be in another
4644 // register if it survives the runtime call.
4645 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck)
4646 ? obj
4647 : out;
4648 __ LoadFromOffset(kLoadWord, target, obj, class_offset);
4649 __ MaybeUnpoisonHeapReference(target);
4650
4651 switch (instruction->GetTypeCheckKind()) {
4652 case TypeCheckKind::kExactCheck: {
4653 __ cmp(out, ShifterOperand(cls));
4654 // Classes must be equal for the instanceof to succeed.
4655 __ b(&zero, NE);
4656 __ LoadImmediate(out, 1);
4657 __ b(&done);
4658 break;
4659 }
4660 case TypeCheckKind::kAbstractClassCheck: {
4661 // If the class is abstract, we eagerly fetch the super class of the
4662 // object to avoid doing a comparison we know will fail.
4663 Label loop;
4664 __ Bind(&loop);
4665 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4666 __ MaybeUnpoisonHeapReference(out);
4667 // If `out` is null, we use it for the result, and jump to `done`.
4668 __ CompareAndBranchIfZero(out, &done);
4669 __ cmp(out, ShifterOperand(cls));
4670 __ b(&loop, NE);
4671 __ LoadImmediate(out, 1);
4672 if (zero.IsLinked()) {
4673 __ b(&done);
4674 }
4675 break;
4676 }
4677 case TypeCheckKind::kClassHierarchyCheck: {
4678 // Walk over the class hierarchy to find a match.
4679 Label loop, success;
4680 __ Bind(&loop);
4681 __ cmp(out, ShifterOperand(cls));
4682 __ b(&success, EQ);
4683 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4684 __ MaybeUnpoisonHeapReference(out);
4685 __ CompareAndBranchIfNonZero(out, &loop);
4686 // If `out` is null, we use it for the result, and jump to `done`.
4687 __ b(&done);
4688 __ Bind(&success);
4689 __ LoadImmediate(out, 1);
4690 if (zero.IsLinked()) {
4691 __ b(&done);
4692 }
4693 break;
4694 }
4695 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004696 // Do an exact check.
4697 Label exact_check;
4698 __ cmp(out, ShifterOperand(cls));
4699 __ b(&exact_check, EQ);
4700 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004701 __ LoadFromOffset(kLoadWord, out, out, component_offset);
4702 __ MaybeUnpoisonHeapReference(out);
4703 // If `out` is null, we use it for the result, and jump to `done`.
4704 __ CompareAndBranchIfZero(out, &done);
4705 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
4706 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4707 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004708 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004709 __ LoadImmediate(out, 1);
4710 __ b(&done);
4711 break;
4712 }
4713 case TypeCheckKind::kArrayCheck: {
4714 __ cmp(out, ShifterOperand(cls));
4715 DCHECK(locations->OnlyCallsOnSlowPath());
4716 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4717 instruction, /* is_fatal */ false);
4718 codegen_->AddSlowPath(slow_path);
4719 __ b(slow_path->GetEntryLabel(), NE);
4720 __ LoadImmediate(out, 1);
4721 if (zero.IsLinked()) {
4722 __ b(&done);
4723 }
4724 break;
4725 }
4726
4727 case TypeCheckKind::kInterfaceCheck:
4728 default: {
4729 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
4730 instruction,
4731 instruction->GetDexPc(),
4732 nullptr);
4733 if (zero.IsLinked()) {
4734 __ b(&done);
4735 }
4736 break;
4737 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004738 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004739
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004740 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004741 __ Bind(&zero);
4742 __ LoadImmediate(out, 0);
4743 }
4744
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004745 if (done.IsLinked()) {
4746 __ Bind(&done);
4747 }
4748
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004749 if (slow_path != nullptr) {
4750 __ Bind(slow_path->GetExitLabel());
4751 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004752}
4753
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004754void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004755 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4756 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
4757
4758 switch (instruction->GetTypeCheckKind()) {
4759 case TypeCheckKind::kExactCheck:
4760 case TypeCheckKind::kAbstractClassCheck:
4761 case TypeCheckKind::kClassHierarchyCheck:
4762 case TypeCheckKind::kArrayObjectCheck:
4763 call_kind = throws_into_catch
4764 ? LocationSummary::kCallOnSlowPath
4765 : LocationSummary::kNoCall;
4766 break;
4767 case TypeCheckKind::kInterfaceCheck:
4768 call_kind = LocationSummary::kCall;
4769 break;
4770 case TypeCheckKind::kArrayCheck:
4771 call_kind = LocationSummary::kCallOnSlowPath;
4772 break;
4773 }
4774
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004775 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004776 instruction, call_kind);
4777 if (call_kind != LocationSummary::kCall) {
4778 locations->SetInAt(0, Location::RequiresRegister());
4779 locations->SetInAt(1, Location::RequiresRegister());
4780 // Note that TypeCheckSlowPathARM uses this register too.
4781 locations->AddTemp(Location::RequiresRegister());
4782 } else {
4783 InvokeRuntimeCallingConvention calling_convention;
4784 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4785 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4786 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004787}
4788
4789void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
4790 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004791 Register obj = locations->InAt(0).AsRegister<Register>();
4792 Register cls = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004793 Register temp = locations->WillCall()
4794 ? Register(kNoRegister)
4795 : locations->GetTemp(0).AsRegister<Register>();
4796
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004797 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004798 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4799 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4800 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
4801 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004802
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004803 if (!locations->WillCall()) {
4804 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4805 instruction, !locations->CanCall());
4806 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray64acf302015-09-14 22:20:29 +01004807 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004808
4809 Label done;
4810 // Avoid null check if we know obj is not null.
4811 if (instruction->MustDoNullCheck()) {
4812 __ CompareAndBranchIfZero(obj, &done);
4813 }
4814
4815 if (locations->WillCall()) {
4816 __ LoadFromOffset(kLoadWord, obj, obj, class_offset);
4817 __ MaybeUnpoisonHeapReference(obj);
4818 } else {
4819 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
4820 __ MaybeUnpoisonHeapReference(temp);
4821 }
4822
4823 switch (instruction->GetTypeCheckKind()) {
4824 case TypeCheckKind::kExactCheck:
4825 case TypeCheckKind::kArrayCheck: {
4826 __ cmp(temp, ShifterOperand(cls));
4827 // Jump to slow path for throwing the exception or doing a
4828 // more involved array check.
4829 __ b(slow_path->GetEntryLabel(), NE);
4830 break;
4831 }
4832 case TypeCheckKind::kAbstractClassCheck: {
4833 // If the class is abstract, we eagerly fetch the super class of the
4834 // object to avoid doing a comparison we know will fail.
4835 Label loop;
4836 __ Bind(&loop);
4837 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
4838 __ MaybeUnpoisonHeapReference(temp);
4839 // Jump to the slow path to throw the exception.
4840 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
4841 __ cmp(temp, ShifterOperand(cls));
4842 __ b(&loop, NE);
4843 break;
4844 }
4845 case TypeCheckKind::kClassHierarchyCheck: {
4846 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004847 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004848 __ Bind(&loop);
4849 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004850 __ b(&done, EQ);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004851 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
4852 __ MaybeUnpoisonHeapReference(temp);
4853 __ CompareAndBranchIfNonZero(temp, &loop);
4854 // Jump to the slow path to throw the exception.
4855 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004856 break;
4857 }
4858 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004859 // Do an exact check.
4860 __ cmp(temp, ShifterOperand(cls));
4861 __ b(&done, EQ);
4862 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004863 __ LoadFromOffset(kLoadWord, temp, temp, component_offset);
4864 __ MaybeUnpoisonHeapReference(temp);
4865 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
4866 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
4867 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4868 __ CompareAndBranchIfNonZero(temp, slow_path->GetEntryLabel());
4869 break;
4870 }
4871 case TypeCheckKind::kInterfaceCheck:
4872 default:
4873 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
4874 instruction,
4875 instruction->GetDexPc(),
4876 nullptr);
4877 break;
4878 }
4879 __ Bind(&done);
4880
4881 if (slow_path != nullptr) {
4882 __ Bind(slow_path->GetExitLabel());
4883 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004884}
4885
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004886void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4887 LocationSummary* locations =
4888 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4889 InvokeRuntimeCallingConvention calling_convention;
4890 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4891}
4892
4893void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4894 codegen_->InvokeRuntime(instruction->IsEnter()
4895 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
4896 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004897 instruction->GetDexPc(),
4898 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004899}
4900
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004901void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4902void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4903void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4904
4905void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4906 LocationSummary* locations =
4907 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4908 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4909 || instruction->GetResultType() == Primitive::kPrimLong);
4910 locations->SetInAt(0, Location::RequiresRegister());
4911 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004912 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004913}
4914
4915void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
4916 HandleBitwiseOperation(instruction);
4917}
4918
4919void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
4920 HandleBitwiseOperation(instruction);
4921}
4922
4923void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
4924 HandleBitwiseOperation(instruction);
4925}
4926
4927void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4928 LocationSummary* locations = instruction->GetLocations();
4929
4930 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004931 Register first = locations->InAt(0).AsRegister<Register>();
4932 Register second = locations->InAt(1).AsRegister<Register>();
4933 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004934 if (instruction->IsAnd()) {
4935 __ and_(out, first, ShifterOperand(second));
4936 } else if (instruction->IsOr()) {
4937 __ orr(out, first, ShifterOperand(second));
4938 } else {
4939 DCHECK(instruction->IsXor());
4940 __ eor(out, first, ShifterOperand(second));
4941 }
4942 } else {
4943 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4944 Location first = locations->InAt(0);
4945 Location second = locations->InAt(1);
4946 Location out = locations->Out();
4947 if (instruction->IsAnd()) {
4948 __ and_(out.AsRegisterPairLow<Register>(),
4949 first.AsRegisterPairLow<Register>(),
4950 ShifterOperand(second.AsRegisterPairLow<Register>()));
4951 __ and_(out.AsRegisterPairHigh<Register>(),
4952 first.AsRegisterPairHigh<Register>(),
4953 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4954 } else if (instruction->IsOr()) {
4955 __ orr(out.AsRegisterPairLow<Register>(),
4956 first.AsRegisterPairLow<Register>(),
4957 ShifterOperand(second.AsRegisterPairLow<Register>()));
4958 __ orr(out.AsRegisterPairHigh<Register>(),
4959 first.AsRegisterPairHigh<Register>(),
4960 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4961 } else {
4962 DCHECK(instruction->IsXor());
4963 __ eor(out.AsRegisterPairLow<Register>(),
4964 first.AsRegisterPairLow<Register>(),
4965 ShifterOperand(second.AsRegisterPairLow<Register>()));
4966 __ eor(out.AsRegisterPairHigh<Register>(),
4967 first.AsRegisterPairHigh<Register>(),
4968 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4969 }
4970 }
4971}
4972
Nicolas Geoffray38207af2015-06-01 15:46:22 +01004973void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00004974 // For better instruction scheduling we load the direct code pointer before the method pointer.
4975 bool direct_code_loaded = false;
4976 switch (invoke->GetCodePtrLocation()) {
4977 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4978 if (IsSameDexFile(*invoke->GetTargetMethod().dex_file, GetGraph()->GetDexFile())) {
4979 break;
4980 }
4981 // Calls across dex files are more likely to exceed the available BL range,
4982 // so use absolute patch by falling through to kDirectCodeFixup.
4983 FALLTHROUGH_INTENDED;
4984 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4985 // LR = code address from literal pool with link-time patch.
4986 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
4987 direct_code_loaded = true;
4988 break;
4989 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4990 // LR = invoke->GetDirectCodePtr();
4991 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
4992 direct_code_loaded = true;
4993 break;
4994 default:
4995 break;
4996 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004997
Vladimir Marko58155012015-08-19 12:49:41 +00004998 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
4999 switch (invoke->GetMethodLoadKind()) {
5000 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
5001 // temp = thread->string_init_entrypoint
5002 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
5003 break;
5004 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
5005 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
5006 break;
5007 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
5008 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
5009 break;
5010 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
5011 __ LoadLiteral(temp.AsRegister<Register>(),
5012 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
5013 break;
5014 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
5015 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
5016 FALLTHROUGH_INTENDED;
5017 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
5018 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
5019 Register method_reg;
5020 Register reg = temp.AsRegister<Register>();
5021 if (current_method.IsRegister()) {
5022 method_reg = current_method.AsRegister<Register>();
5023 } else {
5024 DCHECK(invoke->GetLocations()->Intrinsified());
5025 DCHECK(!current_method.IsValid());
5026 method_reg = reg;
5027 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
5028 }
5029 // temp = current_method->dex_cache_resolved_methods_;
5030 __ LoadFromOffset(
Vladimir Marko05792b92015-08-03 11:56:49 +01005031 kLoadWord, reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset(
5032 kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00005033 // temp = temp[index_in_cache]
5034 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
5035 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
5036 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01005037 }
Vladimir Marko58155012015-08-19 12:49:41 +00005038 }
5039
5040 switch (invoke->GetCodePtrLocation()) {
5041 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
5042 __ bl(GetFrameEntryLabel());
5043 break;
5044 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
5045 if (!direct_code_loaded) {
5046 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
5047 __ Bind(&relative_call_patches_.back().label);
5048 Label label;
5049 __ bl(&label); // Arbitrarily branch to the instruction after BL, override at link time.
5050 __ Bind(&label);
5051 break;
5052 }
5053 // If we loaded the direct code above, fall through.
5054 FALLTHROUGH_INTENDED;
5055 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
5056 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
5057 // LR prepared above for better instruction scheduling.
5058 DCHECK(direct_code_loaded);
5059 // LR()
5060 __ blx(LR);
5061 break;
5062 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
5063 // LR = callee_method->entry_point_from_quick_compiled_code_
5064 __ LoadFromOffset(
5065 kLoadWord, LR, callee_method.AsRegister<Register>(),
5066 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
5067 // LR()
5068 __ blx(LR);
5069 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005070 }
5071
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005072 DCHECK(!IsLeafMethod());
5073}
5074
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005075void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
5076 Register temp = temp_location.AsRegister<Register>();
5077 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5078 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
5079 LocationSummary* locations = invoke->GetLocations();
5080 Location receiver = locations->InAt(0);
5081 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5082 // temp = object->GetClass();
5083 DCHECK(receiver.IsRegister());
5084 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
5085 MaybeRecordImplicitNullCheck(invoke);
5086 __ MaybeUnpoisonHeapReference(temp);
5087 // temp = temp->GetMethodAt(method_offset);
5088 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
5089 kArmWordSize).Int32Value();
5090 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
5091 // LR = temp->GetEntryPoint();
5092 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
5093 // LR();
5094 __ blx(LR);
5095}
5096
Vladimir Marko58155012015-08-19 12:49:41 +00005097void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
5098 DCHECK(linker_patches->empty());
5099 size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
5100 linker_patches->reserve(size);
5101 for (const auto& entry : method_patches_) {
5102 const MethodReference& target_method = entry.first;
5103 Literal* literal = entry.second;
5104 DCHECK(literal->GetLabel()->IsBound());
5105 uint32_t literal_offset = literal->GetLabel()->Position();
5106 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
5107 target_method.dex_file,
5108 target_method.dex_method_index));
5109 }
5110 for (const auto& entry : call_patches_) {
5111 const MethodReference& target_method = entry.first;
5112 Literal* literal = entry.second;
5113 DCHECK(literal->GetLabel()->IsBound());
5114 uint32_t literal_offset = literal->GetLabel()->Position();
5115 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
5116 target_method.dex_file,
5117 target_method.dex_method_index));
5118 }
5119 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
5120 uint32_t literal_offset = info.label.Position();
5121 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
5122 info.target_method.dex_file,
5123 info.target_method.dex_method_index));
5124 }
5125}
5126
5127Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
5128 MethodToLiteralMap* map) {
5129 // Look up the literal for target_method.
5130 auto lb = map->lower_bound(target_method);
5131 if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
5132 return lb->second;
5133 }
5134 // We don't have a literal for this method yet, insert a new one.
5135 Literal* literal = __ NewLiteral<uint32_t>(0u);
5136 map->PutBefore(lb, target_method, literal);
5137 return literal;
5138}
5139
5140Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
5141 return DeduplicateMethodLiteral(target_method, &method_patches_);
5142}
5143
5144Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
5145 return DeduplicateMethodLiteral(target_method, &call_patches_);
5146}
5147
Calin Juravleb1498f62015-02-16 13:13:29 +00005148void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
5149 // Nothing to do, this should be removed during prepare for register allocator.
5150 UNUSED(instruction);
5151 LOG(FATAL) << "Unreachable";
5152}
5153
5154void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
5155 // Nothing to do, this should be removed during prepare for register allocator.
5156 UNUSED(instruction);
5157 LOG(FATAL) << "Unreachable";
5158}
5159
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005160void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
5161 DCHECK(codegen_->IsBaseline());
5162 LocationSummary* locations =
5163 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5164 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5165}
5166
5167void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5168 DCHECK(codegen_->IsBaseline());
5169 // Will be generated at use site.
5170}
5171
Mark Mendellfe57faa2015-09-18 09:26:15 -04005172// Simple implementation of packed switch - generate cascaded compare/jumps.
5173void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5174 LocationSummary* locations =
5175 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5176 locations->SetInAt(0, Location::RequiresRegister());
5177}
5178
5179void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5180 int32_t lower_bound = switch_instr->GetStartValue();
5181 int32_t num_entries = switch_instr->GetNumEntries();
5182 LocationSummary* locations = switch_instr->GetLocations();
5183 Register value_reg = locations->InAt(0).AsRegister<Register>();
5184 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5185
5186 // Create a series of compare/jumps.
5187 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5188 for (int32_t i = 0; i < num_entries; i++) {
5189 GenerateCompareWithImmediate(value_reg, lower_bound + i);
5190 __ b(codegen_->GetLabelOf(successors.at(i)), EQ);
5191 }
5192
5193 // And the default for any other value.
5194 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5195 __ b(codegen_->GetLabelOf(default_block));
5196 }
5197}
5198
Andreas Gampe85b62f22015-09-09 13:15:38 -07005199void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
5200 if (!trg.IsValid()) {
5201 DCHECK(type == Primitive::kPrimVoid);
5202 return;
5203 }
5204
5205 DCHECK_NE(type, Primitive::kPrimVoid);
5206
5207 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
5208 if (return_loc.Equals(trg)) {
5209 return;
5210 }
5211
5212 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
5213 // with the last branch.
5214 if (type == Primitive::kPrimLong) {
5215 HParallelMove parallel_move(GetGraph()->GetArena());
5216 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
5217 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
5218 GetMoveResolver()->EmitNativeCode(&parallel_move);
5219 } else if (type == Primitive::kPrimDouble) {
5220 HParallelMove parallel_move(GetGraph()->GetArena());
5221 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
5222 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
5223 GetMoveResolver()->EmitNativeCode(&parallel_move);
5224 } else {
5225 // Let the parallel move resolver take care of all of this.
5226 HParallelMove parallel_move(GetGraph()->GetArena());
5227 parallel_move.AddMove(return_loc, trg, type, nullptr);
5228 GetMoveResolver()->EmitNativeCode(&parallel_move);
5229 }
5230}
5231
Roland Levillain4d027112015-07-01 15:41:14 +01005232#undef __
5233#undef QUICK_ENTRY_POINT
5234
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00005235} // namespace arm
5236} // namespace art