blob: 31498dc94eaa6273e1a74d84a57c978870618f66 [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 Geoffrayb5f62b32014-10-30 10:58:41 +0000364#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100365#define __ down_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700366
Roland Levillain4fa13f62015-07-06 18:11:54 +0100367inline Condition ARMSignedOrFPCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700368 switch (cond) {
369 case kCondEQ: return EQ;
370 case kCondNE: return NE;
371 case kCondLT: return LT;
372 case kCondLE: return LE;
373 case kCondGT: return GT;
374 case kCondGE: return GE;
Dave Allison20dfc792014-06-16 20:44:29 -0700375 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100376 LOG(FATAL) << "Unreachable";
377 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700378}
379
Roland Levillain4fa13f62015-07-06 18:11:54 +0100380inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700381 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100382 case kCondEQ: return EQ;
383 case kCondNE: return NE;
384 case kCondLT: return LO;
385 case kCondLE: return LS;
386 case kCondGT: return HI;
387 case kCondGE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700388 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100389 LOG(FATAL) << "Unreachable";
390 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700391}
392
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100393void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100394 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100395}
396
397void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100398 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100399}
400
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100401size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
402 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
403 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100404}
405
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100406size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
407 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
408 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100409}
410
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000411size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
412 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
413 return kArmWordSize;
414}
415
416size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
417 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
418 return kArmWordSize;
419}
420
Calin Juravle34166012014-12-19 17:22:29 +0000421CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000422 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100423 const CompilerOptions& compiler_options,
424 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000425 : CodeGenerator(graph,
426 kNumberOfCoreRegisters,
427 kNumberOfSRegisters,
428 kNumberOfRegisterPairs,
429 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
430 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray88a95ba2015-09-30 17:18:14 +0100431 graph->IsDebuggable()
432 // If the graph is debuggable, we need to save the fpu registers ourselves,
433 // as the stubs do not do it.
434 ? 0
435 : ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
436 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100437 compiler_options,
438 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100439 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100440 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100441 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100442 move_resolver_(graph->GetArena(), this),
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000443 assembler_(),
Vladimir Marko58155012015-08-19 12:49:41 +0000444 isa_features_(isa_features),
445 method_patches_(MethodReferenceComparator(), graph->GetArena()->Adapter()),
446 call_patches_(MethodReferenceComparator(), graph->GetArena()->Adapter()),
447 relative_call_patches_(graph->GetArena()->Adapter()) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700448 // Always save the LR register to mimic Quick.
449 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100450}
451
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000452void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
453 // Ensure that we fix up branches and literal loads and emit the literal pool.
454 __ FinalizeCode();
455
456 // Adjust native pc offsets in stack maps.
457 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
458 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
459 uint32_t new_position = __ GetAdjustedPosition(old_position);
460 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
461 }
462 // Adjust native pc offsets of block labels.
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100463 for (HBasicBlock* block : *block_order_) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000464 // Get the label directly from block_labels_ rather than through GetLabelOf() to avoid
465 // FirstNonEmptyBlock() which could lead to adjusting a label more than once.
Vladimir Marko225b6462015-09-28 12:17:40 +0100466 DCHECK_LT(block->GetBlockId(), GetGraph()->GetBlocks().size());
467 Label* block_label = &block_labels_[block->GetBlockId()];
David Brazdilfc6a86a2015-06-26 10:33:45 +0000468 DCHECK_EQ(block_label->IsBound(), !block->IsSingleJump());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000469 if (block_label->IsBound()) {
470 __ AdjustLabelPosition(block_label);
471 }
472 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100473 // Adjust pc offsets for the disassembly information.
474 if (disasm_info_ != nullptr) {
475 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
476 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
477 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
478 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
479 it.second.start = __ GetAdjustedPosition(it.second.start);
480 it.second.end = __ GetAdjustedPosition(it.second.end);
481 }
482 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
483 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
484 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
485 }
486 }
Vladimir Marko58155012015-08-19 12:49:41 +0000487 // Adjust pc offsets for relative call patches.
488 for (MethodPatchInfo<Label>& info : relative_call_patches_) {
489 __ AdjustLabelPosition(&info.label);
490 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000491
492 CodeGenerator::Finalize(allocator);
493}
494
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100495Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100496 switch (type) {
497 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100498 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100499 ArmManagedRegister pair =
500 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100501 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
502 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
503
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100504 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
505 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100506 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100507 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100508 }
509
510 case Primitive::kPrimByte:
511 case Primitive::kPrimBoolean:
512 case Primitive::kPrimChar:
513 case Primitive::kPrimShort:
514 case Primitive::kPrimInt:
515 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100516 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100517 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100518 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
519 ArmManagedRegister current =
520 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
521 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100522 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100523 }
524 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100525 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100526 }
527
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000528 case Primitive::kPrimFloat: {
529 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100530 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100531 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100532
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000533 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000534 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
535 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000536 return Location::FpuRegisterPairLocation(reg, reg + 1);
537 }
538
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100539 case Primitive::kPrimVoid:
540 LOG(FATAL) << "Unreachable type " << type;
541 }
542
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100543 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100544}
545
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000546void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100547 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100548 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100549
550 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100551 blocked_core_registers_[SP] = true;
552 blocked_core_registers_[LR] = true;
553 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100554
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100555 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100556 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100557
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100558 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100559 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100560
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000561 if (is_baseline) {
562 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
563 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
564 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000565
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000566 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
567
568 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
569 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
570 }
571 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100572
573 UpdateBlockedPairRegisters();
574}
575
576void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
577 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
578 ArmManagedRegister current =
579 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
580 if (blocked_core_registers_[current.AsRegisterPairLow()]
581 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
582 blocked_register_pairs_[i] = true;
583 }
584 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100585}
586
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100587InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
588 : HGraphVisitor(graph),
589 assembler_(codegen->GetAssembler()),
590 codegen_(codegen) {}
591
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000592void CodeGeneratorARM::ComputeSpillMask() {
593 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000594 // Save one extra register for baseline. Note that on thumb2, there is no easy
595 // instruction to restore just the PC, so this actually helps both baseline
596 // and non-baseline to save and restore at least two registers at entry and exit.
597 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000598 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
599 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
600 // We use vpush and vpop for saving and restoring floating point registers, which take
601 // a SRegister and the number of registers to save/restore after that SRegister. We
602 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
603 // but in the range.
604 if (fpu_spill_mask_ != 0) {
605 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
606 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
607 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
608 fpu_spill_mask_ |= (1 << i);
609 }
610 }
611}
612
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100613static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100614 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100615}
616
617static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100618 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100619}
620
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000621void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000622 bool skip_overflow_check =
623 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000624 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000625 __ Bind(&frame_entry_label_);
626
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000627 if (HasEmptyFrame()) {
628 return;
629 }
630
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100631 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000632 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
633 __ LoadFromOffset(kLoadWord, IP, IP, 0);
634 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100635 }
636
Andreas Gampe501fd632015-09-10 16:11:06 -0700637 __ PushList(core_spill_mask_);
638 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
639 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000640 if (fpu_spill_mask_ != 0) {
641 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
642 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100643 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100644 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000645 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100646 int adjust = GetFrameSize() - FrameEntrySpillSize();
647 __ AddConstant(SP, -adjust);
648 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100649 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000650}
651
652void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000653 if (HasEmptyFrame()) {
654 __ bx(LR);
655 return;
656 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100657 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100658 int adjust = GetFrameSize() - FrameEntrySpillSize();
659 __ AddConstant(SP, adjust);
660 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000661 if (fpu_spill_mask_ != 0) {
662 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
663 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100664 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
665 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000666 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700667 // Pop LR into PC to return.
668 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
669 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
670 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100671 __ cfi().RestoreState();
672 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000673}
674
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100675void CodeGeneratorARM::Bind(HBasicBlock* block) {
676 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000677}
678
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100679Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
680 switch (load->GetType()) {
681 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100682 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100683 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100684
685 case Primitive::kPrimInt:
686 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100687 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100688 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100689
690 case Primitive::kPrimBoolean:
691 case Primitive::kPrimByte:
692 case Primitive::kPrimChar:
693 case Primitive::kPrimShort:
694 case Primitive::kPrimVoid:
695 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700696 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100697 }
698
699 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700700 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100701}
702
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100703Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100704 switch (type) {
705 case Primitive::kPrimBoolean:
706 case Primitive::kPrimByte:
707 case Primitive::kPrimChar:
708 case Primitive::kPrimShort:
709 case Primitive::kPrimInt:
710 case Primitive::kPrimNot: {
711 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000712 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100713 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100714 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100715 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000716 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100717 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100718 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100719
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000720 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100721 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000722 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100723 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000724 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100725 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000726 if (calling_convention.GetRegisterAt(index) == R1) {
727 // Skip R1, and use R2_R3 instead.
728 gp_index_++;
729 index++;
730 }
731 }
732 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
733 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000734 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +0100735
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000736 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000737 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100738 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000739 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
740 }
741 }
742
743 case Primitive::kPrimFloat: {
744 uint32_t stack_index = stack_index_++;
745 if (float_index_ % 2 == 0) {
746 float_index_ = std::max(double_index_, float_index_);
747 }
748 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
749 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
750 } else {
751 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
752 }
753 }
754
755 case Primitive::kPrimDouble: {
756 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
757 uint32_t stack_index = stack_index_;
758 stack_index_ += 2;
759 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
760 uint32_t index = double_index_;
761 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000762 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000763 calling_convention.GetFpuRegisterAt(index),
764 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000765 DCHECK(ExpectedPairLayout(result));
766 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000767 } else {
768 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100769 }
770 }
771
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100772 case Primitive::kPrimVoid:
773 LOG(FATAL) << "Unexpected parameter type " << type;
774 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100775 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100776 return Location();
777}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100778
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100779Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000780 switch (type) {
781 case Primitive::kPrimBoolean:
782 case Primitive::kPrimByte:
783 case Primitive::kPrimChar:
784 case Primitive::kPrimShort:
785 case Primitive::kPrimInt:
786 case Primitive::kPrimNot: {
787 return Location::RegisterLocation(R0);
788 }
789
790 case Primitive::kPrimFloat: {
791 return Location::FpuRegisterLocation(S0);
792 }
793
794 case Primitive::kPrimLong: {
795 return Location::RegisterPairLocation(R0, R1);
796 }
797
798 case Primitive::kPrimDouble: {
799 return Location::FpuRegisterPairLocation(S0, S1);
800 }
801
802 case Primitive::kPrimVoid:
803 return Location();
804 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100805
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000806 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000807}
808
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100809Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
810 return Location::RegisterLocation(kMethodRegisterArgument);
811}
812
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100813void CodeGeneratorARM::Move32(Location destination, Location source) {
814 if (source.Equals(destination)) {
815 return;
816 }
817 if (destination.IsRegister()) {
818 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000819 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100820 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000821 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100822 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000823 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100824 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100825 } else if (destination.IsFpuRegister()) {
826 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000827 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100828 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000829 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100830 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000831 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100832 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100833 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000834 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100835 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000836 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100837 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000838 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100839 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000840 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100841 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
842 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100843 }
844 }
845}
846
847void CodeGeneratorARM::Move64(Location destination, Location source) {
848 if (source.Equals(destination)) {
849 return;
850 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100851 if (destination.IsRegisterPair()) {
852 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000853 EmitParallelMoves(
854 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
855 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100856 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000857 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100858 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
859 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100860 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000861 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100862 } else {
863 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000864 DCHECK(ExpectedPairLayout(destination));
865 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
866 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100867 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000868 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100869 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000870 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
871 SP,
872 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100873 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000874 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100875 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100876 } else {
877 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100878 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000879 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100880 if (source.AsRegisterPairLow<Register>() == R1) {
881 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100882 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
883 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100884 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100885 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100886 SP, destination.GetStackIndex());
887 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000888 } else if (source.IsFpuRegisterPair()) {
889 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
890 SP,
891 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100892 } else {
893 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000894 EmitParallelMoves(
895 Location::StackSlot(source.GetStackIndex()),
896 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100897 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000898 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100899 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
900 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100901 }
902 }
903}
904
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100905void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100906 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100907 if (instruction->IsCurrentMethod()) {
908 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
909 } else if (locations != nullptr && locations->Out().Equals(location)) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100910 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100911 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000912 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000913 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
914 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +0000915 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000916 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000917 } else {
918 DCHECK(location.IsStackSlot());
919 __ LoadImmediate(IP, value);
920 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
921 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000922 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000923 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000924 int64_t value = const_to_move->AsLongConstant()->GetValue();
925 if (location.IsRegisterPair()) {
926 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
927 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
928 } else {
929 DCHECK(location.IsDoubleStackSlot());
930 __ LoadImmediate(IP, Low32Bits(value));
931 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
932 __ LoadImmediate(IP, High32Bits(value));
933 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
934 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100935 }
Roland Levillain476df552014-10-09 17:51:36 +0100936 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100937 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
938 switch (instruction->GetType()) {
939 case Primitive::kPrimBoolean:
940 case Primitive::kPrimByte:
941 case Primitive::kPrimChar:
942 case Primitive::kPrimShort:
943 case Primitive::kPrimInt:
944 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100945 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100946 Move32(location, Location::StackSlot(stack_slot));
947 break;
948
949 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100950 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100951 Move64(location, Location::DoubleStackSlot(stack_slot));
952 break;
953
954 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100955 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100956 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000957 } else if (instruction->IsTemporary()) {
958 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000959 if (temp_location.IsStackSlot()) {
960 Move32(location, temp_location);
961 } else {
962 DCHECK(temp_location.IsDoubleStackSlot());
963 Move64(location, temp_location);
964 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000965 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100966 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100967 switch (instruction->GetType()) {
968 case Primitive::kPrimBoolean:
969 case Primitive::kPrimByte:
970 case Primitive::kPrimChar:
971 case Primitive::kPrimShort:
972 case Primitive::kPrimNot:
973 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100974 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100975 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100976 break;
977
978 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100979 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100980 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100981 break;
982
983 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100984 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100985 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000986 }
987}
988
Calin Juravle175dc732015-08-25 15:42:32 +0100989void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
990 DCHECK(location.IsRegister());
991 __ LoadImmediate(location.AsRegister<Register>(), value);
992}
993
994void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
995 HInstruction* instruction,
996 uint32_t dex_pc,
997 SlowPathCode* slow_path) {
998 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
999 instruction,
1000 dex_pc,
1001 slow_path);
1002}
1003
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001004void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1005 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001006 uint32_t dex_pc,
1007 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001008 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001009 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1010 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001011 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001012}
1013
David Brazdilfc6a86a2015-06-26 10:33:45 +00001014void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001015 DCHECK(!successor->IsExitBlock());
1016
1017 HBasicBlock* block = got->GetBlock();
1018 HInstruction* previous = got->GetPrevious();
1019
1020 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001021 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001022 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1023 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1024 return;
1025 }
1026
1027 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1028 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1029 }
1030 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001031 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001032 }
1033}
1034
David Brazdilfc6a86a2015-06-26 10:33:45 +00001035void LocationsBuilderARM::VisitGoto(HGoto* got) {
1036 got->SetLocations(nullptr);
1037}
1038
1039void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1040 HandleGoto(got, got->GetSuccessor());
1041}
1042
1043void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1044 try_boundary->SetLocations(nullptr);
1045}
1046
1047void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1048 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1049 if (!successor->IsExitBlock()) {
1050 HandleGoto(try_boundary, successor);
1051 }
1052}
1053
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001054void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001055 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001056}
1057
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001058void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001059 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001060}
1061
Roland Levillain4fa13f62015-07-06 18:11:54 +01001062void InstructionCodeGeneratorARM::GenerateCompareWithImmediate(Register left, int32_t right) {
1063 ShifterOperand operand;
1064 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, right, &operand)) {
1065 __ cmp(left, operand);
1066 } else {
1067 Register temp = IP;
1068 __ LoadImmediate(temp, right);
1069 __ cmp(left, ShifterOperand(temp));
1070 }
1071}
1072
1073void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1074 Label* true_label,
1075 Label* false_label) {
1076 __ vmstat(); // transfer FP status register to ARM APSR.
1077 if (cond->IsFPConditionTrueIfNaN()) {
1078 __ b(true_label, VS); // VS for unordered.
1079 } else if (cond->IsFPConditionFalseIfNaN()) {
1080 __ b(false_label, VS); // VS for unordered.
1081 }
1082 __ b(true_label, ARMSignedOrFPCondition(cond->GetCondition()));
1083}
1084
1085void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1086 Label* true_label,
1087 Label* false_label) {
1088 LocationSummary* locations = cond->GetLocations();
1089 Location left = locations->InAt(0);
1090 Location right = locations->InAt(1);
1091 IfCondition if_cond = cond->GetCondition();
1092
1093 Register left_high = left.AsRegisterPairHigh<Register>();
1094 Register left_low = left.AsRegisterPairLow<Register>();
1095 IfCondition true_high_cond = if_cond;
1096 IfCondition false_high_cond = cond->GetOppositeCondition();
1097 Condition final_condition = ARMUnsignedCondition(if_cond);
1098
1099 // Set the conditions for the test, remembering that == needs to be
1100 // decided using the low words.
1101 switch (if_cond) {
1102 case kCondEQ:
1103 case kCondNE:
1104 // Nothing to do.
1105 break;
1106 case kCondLT:
1107 false_high_cond = kCondGT;
1108 break;
1109 case kCondLE:
1110 true_high_cond = kCondLT;
1111 break;
1112 case kCondGT:
1113 false_high_cond = kCondLT;
1114 break;
1115 case kCondGE:
1116 true_high_cond = kCondGT;
1117 break;
1118 }
1119 if (right.IsConstant()) {
1120 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1121 int32_t val_low = Low32Bits(value);
1122 int32_t val_high = High32Bits(value);
1123
1124 GenerateCompareWithImmediate(left_high, val_high);
1125 if (if_cond == kCondNE) {
1126 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1127 } else if (if_cond == kCondEQ) {
1128 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1129 } else {
1130 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1131 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1132 }
1133 // Must be equal high, so compare the lows.
1134 GenerateCompareWithImmediate(left_low, val_low);
1135 } else {
1136 Register right_high = right.AsRegisterPairHigh<Register>();
1137 Register right_low = right.AsRegisterPairLow<Register>();
1138
1139 __ cmp(left_high, ShifterOperand(right_high));
1140 if (if_cond == kCondNE) {
1141 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1142 } else if (if_cond == kCondEQ) {
1143 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1144 } else {
1145 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1146 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1147 }
1148 // Must be equal high, so compare the lows.
1149 __ cmp(left_low, ShifterOperand(right_low));
1150 }
1151 // The last comparison might be unsigned.
1152 __ b(true_label, final_condition);
1153}
1154
1155void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HIf* if_instr,
1156 HCondition* condition,
1157 Label* true_target,
1158 Label* false_target,
1159 Label* always_true_target) {
1160 LocationSummary* locations = condition->GetLocations();
1161 Location left = locations->InAt(0);
1162 Location right = locations->InAt(1);
1163
1164 // We don't want true_target as a nullptr.
1165 if (true_target == nullptr) {
1166 true_target = always_true_target;
1167 }
1168 bool falls_through = (false_target == nullptr);
1169
1170 // FP compares don't like null false_targets.
1171 if (false_target == nullptr) {
1172 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1173 }
1174
1175 Primitive::Type type = condition->InputAt(0)->GetType();
1176 switch (type) {
1177 case Primitive::kPrimLong:
1178 GenerateLongComparesAndJumps(condition, true_target, false_target);
1179 break;
1180 case Primitive::kPrimFloat:
1181 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1182 GenerateFPJumps(condition, true_target, false_target);
1183 break;
1184 case Primitive::kPrimDouble:
1185 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1186 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1187 GenerateFPJumps(condition, true_target, false_target);
1188 break;
1189 default:
1190 LOG(FATAL) << "Unexpected compare type " << type;
1191 }
1192
1193 if (!falls_through) {
1194 __ b(false_target);
1195 }
1196}
1197
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001198void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
1199 Label* true_target,
1200 Label* false_target,
1201 Label* always_true_target) {
1202 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001203 if (cond->IsIntConstant()) {
1204 // Constant condition, statically compared against 1.
1205 int32_t cond_value = cond->AsIntConstant()->GetValue();
1206 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001207 if (always_true_target != nullptr) {
1208 __ b(always_true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001209 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001210 return;
1211 } else {
1212 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001213 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001214 } else {
1215 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1216 // Condition has been materialized, compare the output to 0
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001217 DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01001218 __ CompareAndBranchIfNonZero(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
1219 true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001220 } else {
1221 // Condition has not been materialized, use its inputs as the
1222 // comparison and its condition as the branch condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001223 Primitive::Type type =
1224 cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
1225 // Is this a long or FP comparison that has been folded into the HCondition?
1226 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1227 // Generate the comparison directly.
1228 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
1229 true_target, false_target, always_true_target);
1230 return;
1231 }
1232
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001233 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001234 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001235 Register left = locations->InAt(0).AsRegister<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001236 Location right = locations->InAt(1);
1237 if (right.IsRegister()) {
1238 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001239 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001240 DCHECK(right.IsConstant());
1241 GenerateCompareWithImmediate(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001242 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001243 __ b(true_target, ARMSignedOrFPCondition(cond->AsCondition()->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001244 }
Dave Allison20dfc792014-06-16 20:44:29 -07001245 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001246 if (false_target != nullptr) {
1247 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001248 }
1249}
1250
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001251void LocationsBuilderARM::VisitIf(HIf* if_instr) {
1252 LocationSummary* locations =
1253 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1254 HInstruction* cond = if_instr->InputAt(0);
1255 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1256 locations->SetInAt(0, Location::RequiresRegister());
1257 }
1258}
1259
1260void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
1261 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1262 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1263 Label* always_true_target = true_target;
1264 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1265 if_instr->IfTrueSuccessor())) {
1266 always_true_target = nullptr;
1267 }
1268 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1269 if_instr->IfFalseSuccessor())) {
1270 false_target = nullptr;
1271 }
1272 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1273}
1274
1275void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1276 LocationSummary* locations = new (GetGraph()->GetArena())
1277 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1278 HInstruction* cond = deoptimize->InputAt(0);
1279 DCHECK(cond->IsCondition());
1280 if (cond->AsCondition()->NeedsMaterialization()) {
1281 locations->SetInAt(0, Location::RequiresRegister());
1282 }
1283}
1284
1285void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001286 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001287 DeoptimizationSlowPathARM(deoptimize);
1288 codegen_->AddSlowPath(slow_path);
1289 Label* slow_path_entry = slow_path->GetEntryLabel();
1290 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1291}
Dave Allison20dfc792014-06-16 20:44:29 -07001292
Roland Levillain0d37cd02015-05-27 16:39:19 +01001293void LocationsBuilderARM::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001294 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001295 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001296 // Handle the long/FP comparisons made in instruction simplification.
1297 switch (cond->InputAt(0)->GetType()) {
1298 case Primitive::kPrimLong:
1299 locations->SetInAt(0, Location::RequiresRegister());
1300 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1301 if (cond->NeedsMaterialization()) {
1302 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1303 }
1304 break;
1305
1306 case Primitive::kPrimFloat:
1307 case Primitive::kPrimDouble:
1308 locations->SetInAt(0, Location::RequiresFpuRegister());
1309 locations->SetInAt(1, Location::RequiresFpuRegister());
1310 if (cond->NeedsMaterialization()) {
1311 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1312 }
1313 break;
1314
1315 default:
1316 locations->SetInAt(0, Location::RequiresRegister());
1317 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1318 if (cond->NeedsMaterialization()) {
1319 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1320 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001321 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001322}
1323
Roland Levillain0d37cd02015-05-27 16:39:19 +01001324void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001325 if (!cond->NeedsMaterialization()) {
1326 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001327 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001328
1329 LocationSummary* locations = cond->GetLocations();
1330 Location left = locations->InAt(0);
1331 Location right = locations->InAt(1);
1332 Register out = locations->Out().AsRegister<Register>();
1333 Label true_label, false_label;
1334
1335 switch (cond->InputAt(0)->GetType()) {
1336 default: {
1337 // Integer case.
1338 if (right.IsRegister()) {
1339 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1340 } else {
1341 DCHECK(right.IsConstant());
1342 GenerateCompareWithImmediate(left.AsRegister<Register>(),
1343 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1344 }
1345 __ it(ARMSignedOrFPCondition(cond->GetCondition()), kItElse);
1346 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
1347 ARMSignedOrFPCondition(cond->GetCondition()));
1348 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
1349 ARMSignedOrFPCondition(cond->GetOppositeCondition()));
1350 return;
1351 }
1352 case Primitive::kPrimLong:
1353 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1354 break;
1355 case Primitive::kPrimFloat:
1356 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1357 GenerateFPJumps(cond, &true_label, &false_label);
1358 break;
1359 case Primitive::kPrimDouble:
1360 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1361 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1362 GenerateFPJumps(cond, &true_label, &false_label);
1363 break;
1364 }
1365
1366 // Convert the jumps into the result.
1367 Label done_label;
1368
1369 // False case: result = 0.
1370 __ Bind(&false_label);
1371 __ LoadImmediate(out, 0);
1372 __ b(&done_label);
1373
1374 // True case: result = 1.
1375 __ Bind(&true_label);
1376 __ LoadImmediate(out, 1);
1377 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001378}
1379
1380void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1381 VisitCondition(comp);
1382}
1383
1384void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1385 VisitCondition(comp);
1386}
1387
1388void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1389 VisitCondition(comp);
1390}
1391
1392void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1393 VisitCondition(comp);
1394}
1395
1396void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1397 VisitCondition(comp);
1398}
1399
1400void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1401 VisitCondition(comp);
1402}
1403
1404void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1405 VisitCondition(comp);
1406}
1407
1408void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1409 VisitCondition(comp);
1410}
1411
1412void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1413 VisitCondition(comp);
1414}
1415
1416void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1417 VisitCondition(comp);
1418}
1419
1420void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1421 VisitCondition(comp);
1422}
1423
1424void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1425 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001426}
1427
1428void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001429 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001430}
1431
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001432void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1433 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001434}
1435
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001436void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001437 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001438}
1439
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001440void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001441 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001442 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001443}
1444
1445void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001446 LocationSummary* locations =
1447 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001448 switch (store->InputAt(1)->GetType()) {
1449 case Primitive::kPrimBoolean:
1450 case Primitive::kPrimByte:
1451 case Primitive::kPrimChar:
1452 case Primitive::kPrimShort:
1453 case Primitive::kPrimInt:
1454 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001455 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001456 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1457 break;
1458
1459 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001460 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001461 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1462 break;
1463
1464 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001465 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001466 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001467}
1468
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001469void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001470 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001471}
1472
1473void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001474 LocationSummary* locations =
1475 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001476 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001477}
1478
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001479void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001480 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001481 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001482}
1483
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001484void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1485 LocationSummary* locations =
1486 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1487 locations->SetOut(Location::ConstantLocation(constant));
1488}
1489
1490void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
1491 // Will be generated at use site.
1492 UNUSED(constant);
1493}
1494
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001495void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001496 LocationSummary* locations =
1497 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001498 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001499}
1500
1501void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1502 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001503 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001504}
1505
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001506void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1507 LocationSummary* locations =
1508 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1509 locations->SetOut(Location::ConstantLocation(constant));
1510}
1511
1512void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1513 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001514 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001515}
1516
1517void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1518 LocationSummary* locations =
1519 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1520 locations->SetOut(Location::ConstantLocation(constant));
1521}
1522
1523void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1524 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001525 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001526}
1527
Calin Juravle27df7582015-04-17 19:12:31 +01001528void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1529 memory_barrier->SetLocations(nullptr);
1530}
1531
1532void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1533 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1534}
1535
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001536void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001537 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001538}
1539
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001540void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001541 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001542 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001543}
1544
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001545void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001546 LocationSummary* locations =
1547 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001548 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001549}
1550
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001551void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001552 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001553 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001554}
1555
Calin Juravle175dc732015-08-25 15:42:32 +01001556void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1557 // The trampoline uses the same calling convention as dex calling conventions,
1558 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1559 // the method_idx.
1560 HandleInvoke(invoke);
1561}
1562
1563void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1564 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1565}
1566
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001567void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001568 // When we do not run baseline, explicit clinit checks triggered by static
1569 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1570 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001571
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001572 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1573 codegen_->GetInstructionSetFeatures());
1574 if (intrinsic.TryDispatch(invoke)) {
1575 return;
1576 }
1577
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001578 HandleInvoke(invoke);
1579}
1580
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001581static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1582 if (invoke->GetLocations()->Intrinsified()) {
1583 IntrinsicCodeGeneratorARM intrinsic(codegen);
1584 intrinsic.Dispatch(invoke);
1585 return true;
1586 }
1587 return false;
1588}
1589
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001590void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001591 // When we do not run baseline, explicit clinit checks triggered by static
1592 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1593 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001594
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001595 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1596 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001597 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001598
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001599 LocationSummary* locations = invoke->GetLocations();
1600 codegen_->GenerateStaticOrDirectCall(
1601 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001602 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001603}
1604
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001605void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001606 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001607 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001608}
1609
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001610void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001611 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1612 codegen_->GetInstructionSetFeatures());
1613 if (intrinsic.TryDispatch(invoke)) {
1614 return;
1615 }
1616
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001617 HandleInvoke(invoke);
1618}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001619
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001620void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001621 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1622 return;
1623 }
1624
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001625 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001626 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001627 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001628}
1629
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001630void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1631 HandleInvoke(invoke);
1632 // Add the hidden argument.
1633 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1634}
1635
1636void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1637 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001638 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001639 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1640 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001641 LocationSummary* locations = invoke->GetLocations();
1642 Location receiver = locations->InAt(0);
1643 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1644
1645 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001646 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1647 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001648
1649 // temp = object->GetClass();
1650 if (receiver.IsStackSlot()) {
1651 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1652 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1653 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001654 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001655 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001656 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001657 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001658 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001659 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001660 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001661 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1662 // LR = temp->GetEntryPoint();
1663 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1664 // LR();
1665 __ blx(LR);
1666 DCHECK(!codegen_->IsLeafMethod());
1667 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1668}
1669
Roland Levillain88cb1752014-10-20 16:36:47 +01001670void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1671 LocationSummary* locations =
1672 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1673 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001674 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001675 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001676 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1677 break;
1678 }
1679 case Primitive::kPrimLong: {
1680 locations->SetInAt(0, Location::RequiresRegister());
1681 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001682 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001683 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001684
Roland Levillain88cb1752014-10-20 16:36:47 +01001685 case Primitive::kPrimFloat:
1686 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001687 locations->SetInAt(0, Location::RequiresFpuRegister());
1688 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001689 break;
1690
1691 default:
1692 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1693 }
1694}
1695
1696void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1697 LocationSummary* locations = neg->GetLocations();
1698 Location out = locations->Out();
1699 Location in = locations->InAt(0);
1700 switch (neg->GetResultType()) {
1701 case Primitive::kPrimInt:
1702 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001703 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001704 break;
1705
1706 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001707 DCHECK(in.IsRegisterPair());
1708 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1709 __ rsbs(out.AsRegisterPairLow<Register>(),
1710 in.AsRegisterPairLow<Register>(),
1711 ShifterOperand(0));
1712 // We cannot emit an RSC (Reverse Subtract with Carry)
1713 // instruction here, as it does not exist in the Thumb-2
1714 // instruction set. We use the following approach
1715 // using SBC and SUB instead.
1716 //
1717 // out.hi = -C
1718 __ sbc(out.AsRegisterPairHigh<Register>(),
1719 out.AsRegisterPairHigh<Register>(),
1720 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1721 // out.hi = out.hi - in.hi
1722 __ sub(out.AsRegisterPairHigh<Register>(),
1723 out.AsRegisterPairHigh<Register>(),
1724 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1725 break;
1726
Roland Levillain88cb1752014-10-20 16:36:47 +01001727 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001728 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001729 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001730 break;
1731
Roland Levillain88cb1752014-10-20 16:36:47 +01001732 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001733 DCHECK(in.IsFpuRegisterPair());
1734 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1735 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001736 break;
1737
1738 default:
1739 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1740 }
1741}
1742
Roland Levillaindff1f282014-11-05 14:15:05 +00001743void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001744 Primitive::Type result_type = conversion->GetResultType();
1745 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001746 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001747
Roland Levillain5b3ee562015-04-14 16:02:41 +01001748 // The float-to-long, double-to-long and long-to-float type conversions
1749 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001750 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01001751 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1752 && result_type == Primitive::kPrimLong)
1753 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00001754 ? LocationSummary::kCall
1755 : LocationSummary::kNoCall;
1756 LocationSummary* locations =
1757 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1758
David Brazdilb2bd1c52015-03-25 11:17:37 +00001759 // The Java language does not allow treating boolean as an integral type but
1760 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001761
Roland Levillaindff1f282014-11-05 14:15:05 +00001762 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001763 case Primitive::kPrimByte:
1764 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001765 case Primitive::kPrimBoolean:
1766 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001767 case Primitive::kPrimShort:
1768 case Primitive::kPrimInt:
1769 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001770 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001771 locations->SetInAt(0, Location::RequiresRegister());
1772 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1773 break;
1774
1775 default:
1776 LOG(FATAL) << "Unexpected type conversion from " << input_type
1777 << " to " << result_type;
1778 }
1779 break;
1780
Roland Levillain01a8d712014-11-14 16:27:39 +00001781 case Primitive::kPrimShort:
1782 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001783 case Primitive::kPrimBoolean:
1784 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001785 case Primitive::kPrimByte:
1786 case Primitive::kPrimInt:
1787 case Primitive::kPrimChar:
1788 // Processing a Dex `int-to-short' instruction.
1789 locations->SetInAt(0, Location::RequiresRegister());
1790 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1791 break;
1792
1793 default:
1794 LOG(FATAL) << "Unexpected type conversion from " << input_type
1795 << " to " << result_type;
1796 }
1797 break;
1798
Roland Levillain946e1432014-11-11 17:35:19 +00001799 case Primitive::kPrimInt:
1800 switch (input_type) {
1801 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001802 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001803 locations->SetInAt(0, Location::Any());
1804 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1805 break;
1806
1807 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001808 // Processing a Dex `float-to-int' instruction.
1809 locations->SetInAt(0, Location::RequiresFpuRegister());
1810 locations->SetOut(Location::RequiresRegister());
1811 locations->AddTemp(Location::RequiresFpuRegister());
1812 break;
1813
Roland Levillain946e1432014-11-11 17:35:19 +00001814 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001815 // Processing a Dex `double-to-int' instruction.
1816 locations->SetInAt(0, Location::RequiresFpuRegister());
1817 locations->SetOut(Location::RequiresRegister());
1818 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001819 break;
1820
1821 default:
1822 LOG(FATAL) << "Unexpected type conversion from " << input_type
1823 << " to " << result_type;
1824 }
1825 break;
1826
Roland Levillaindff1f282014-11-05 14:15:05 +00001827 case Primitive::kPrimLong:
1828 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001829 case Primitive::kPrimBoolean:
1830 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001831 case Primitive::kPrimByte:
1832 case Primitive::kPrimShort:
1833 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001834 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001835 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001836 locations->SetInAt(0, Location::RequiresRegister());
1837 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1838 break;
1839
Roland Levillain624279f2014-12-04 11:54:28 +00001840 case Primitive::kPrimFloat: {
1841 // Processing a Dex `float-to-long' instruction.
1842 InvokeRuntimeCallingConvention calling_convention;
1843 locations->SetInAt(0, Location::FpuRegisterLocation(
1844 calling_convention.GetFpuRegisterAt(0)));
1845 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1846 break;
1847 }
1848
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001849 case Primitive::kPrimDouble: {
1850 // Processing a Dex `double-to-long' instruction.
1851 InvokeRuntimeCallingConvention calling_convention;
1852 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1853 calling_convention.GetFpuRegisterAt(0),
1854 calling_convention.GetFpuRegisterAt(1)));
1855 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001856 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001857 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001858
1859 default:
1860 LOG(FATAL) << "Unexpected type conversion from " << input_type
1861 << " to " << result_type;
1862 }
1863 break;
1864
Roland Levillain981e4542014-11-14 11:47:14 +00001865 case Primitive::kPrimChar:
1866 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001867 case Primitive::kPrimBoolean:
1868 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001869 case Primitive::kPrimByte:
1870 case Primitive::kPrimShort:
1871 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001872 // Processing a Dex `int-to-char' instruction.
1873 locations->SetInAt(0, Location::RequiresRegister());
1874 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1875 break;
1876
1877 default:
1878 LOG(FATAL) << "Unexpected type conversion from " << input_type
1879 << " to " << result_type;
1880 }
1881 break;
1882
Roland Levillaindff1f282014-11-05 14:15:05 +00001883 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001884 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001885 case Primitive::kPrimBoolean:
1886 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001887 case Primitive::kPrimByte:
1888 case Primitive::kPrimShort:
1889 case Primitive::kPrimInt:
1890 case Primitive::kPrimChar:
1891 // Processing a Dex `int-to-float' instruction.
1892 locations->SetInAt(0, Location::RequiresRegister());
1893 locations->SetOut(Location::RequiresFpuRegister());
1894 break;
1895
Roland Levillain5b3ee562015-04-14 16:02:41 +01001896 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00001897 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01001898 InvokeRuntimeCallingConvention calling_convention;
1899 locations->SetInAt(0, Location::RegisterPairLocation(
1900 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
1901 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00001902 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01001903 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00001904
Roland Levillaincff13742014-11-17 14:32:17 +00001905 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001906 // Processing a Dex `double-to-float' instruction.
1907 locations->SetInAt(0, Location::RequiresFpuRegister());
1908 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001909 break;
1910
1911 default:
1912 LOG(FATAL) << "Unexpected type conversion from " << input_type
1913 << " to " << result_type;
1914 };
1915 break;
1916
Roland Levillaindff1f282014-11-05 14:15:05 +00001917 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001918 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001919 case Primitive::kPrimBoolean:
1920 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001921 case Primitive::kPrimByte:
1922 case Primitive::kPrimShort:
1923 case Primitive::kPrimInt:
1924 case Primitive::kPrimChar:
1925 // Processing a Dex `int-to-double' instruction.
1926 locations->SetInAt(0, Location::RequiresRegister());
1927 locations->SetOut(Location::RequiresFpuRegister());
1928 break;
1929
1930 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001931 // Processing a Dex `long-to-double' instruction.
1932 locations->SetInAt(0, Location::RequiresRegister());
1933 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01001934 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001935 locations->AddTemp(Location::RequiresFpuRegister());
1936 break;
1937
Roland Levillaincff13742014-11-17 14:32:17 +00001938 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001939 // Processing a Dex `float-to-double' instruction.
1940 locations->SetInAt(0, Location::RequiresFpuRegister());
1941 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001942 break;
1943
1944 default:
1945 LOG(FATAL) << "Unexpected type conversion from " << input_type
1946 << " to " << result_type;
1947 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001948 break;
1949
1950 default:
1951 LOG(FATAL) << "Unexpected type conversion from " << input_type
1952 << " to " << result_type;
1953 }
1954}
1955
1956void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1957 LocationSummary* locations = conversion->GetLocations();
1958 Location out = locations->Out();
1959 Location in = locations->InAt(0);
1960 Primitive::Type result_type = conversion->GetResultType();
1961 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001962 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001963 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001964 case Primitive::kPrimByte:
1965 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001966 case Primitive::kPrimBoolean:
1967 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001968 case Primitive::kPrimShort:
1969 case Primitive::kPrimInt:
1970 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001971 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001972 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001973 break;
1974
1975 default:
1976 LOG(FATAL) << "Unexpected type conversion from " << input_type
1977 << " to " << result_type;
1978 }
1979 break;
1980
Roland Levillain01a8d712014-11-14 16:27:39 +00001981 case Primitive::kPrimShort:
1982 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001983 case Primitive::kPrimBoolean:
1984 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001985 case Primitive::kPrimByte:
1986 case Primitive::kPrimInt:
1987 case Primitive::kPrimChar:
1988 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001989 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00001990 break;
1991
1992 default:
1993 LOG(FATAL) << "Unexpected type conversion from " << input_type
1994 << " to " << result_type;
1995 }
1996 break;
1997
Roland Levillain946e1432014-11-11 17:35:19 +00001998 case Primitive::kPrimInt:
1999 switch (input_type) {
2000 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002001 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002002 DCHECK(out.IsRegister());
2003 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002004 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002005 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002006 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002007 } else {
2008 DCHECK(in.IsConstant());
2009 DCHECK(in.GetConstant()->IsLongConstant());
2010 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002011 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002012 }
2013 break;
2014
Roland Levillain3f8f9362014-12-02 17:45:01 +00002015 case Primitive::kPrimFloat: {
2016 // Processing a Dex `float-to-int' instruction.
2017 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2018 __ vmovs(temp, in.AsFpuRegister<SRegister>());
2019 __ vcvtis(temp, temp);
2020 __ vmovrs(out.AsRegister<Register>(), temp);
2021 break;
2022 }
2023
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002024 case Primitive::kPrimDouble: {
2025 // Processing a Dex `double-to-int' instruction.
2026 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2027 DRegister temp_d = FromLowSToD(temp_s);
2028 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2029 __ vcvtid(temp_s, temp_d);
2030 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002031 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002032 }
Roland Levillain946e1432014-11-11 17:35:19 +00002033
2034 default:
2035 LOG(FATAL) << "Unexpected type conversion from " << input_type
2036 << " to " << result_type;
2037 }
2038 break;
2039
Roland Levillaindff1f282014-11-05 14:15:05 +00002040 case Primitive::kPrimLong:
2041 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002042 case Primitive::kPrimBoolean:
2043 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002044 case Primitive::kPrimByte:
2045 case Primitive::kPrimShort:
2046 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002047 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002048 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002049 DCHECK(out.IsRegisterPair());
2050 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002051 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002052 // Sign extension.
2053 __ Asr(out.AsRegisterPairHigh<Register>(),
2054 out.AsRegisterPairLow<Register>(),
2055 31);
2056 break;
2057
2058 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002059 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002060 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2061 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002062 conversion->GetDexPc(),
2063 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002064 break;
2065
Roland Levillaindff1f282014-11-05 14:15:05 +00002066 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002067 // Processing a Dex `double-to-long' instruction.
2068 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2069 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002070 conversion->GetDexPc(),
2071 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002072 break;
2073
2074 default:
2075 LOG(FATAL) << "Unexpected type conversion from " << input_type
2076 << " to " << result_type;
2077 }
2078 break;
2079
Roland Levillain981e4542014-11-14 11:47:14 +00002080 case Primitive::kPrimChar:
2081 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002082 case Primitive::kPrimBoolean:
2083 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002084 case Primitive::kPrimByte:
2085 case Primitive::kPrimShort:
2086 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002087 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002088 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002089 break;
2090
2091 default:
2092 LOG(FATAL) << "Unexpected type conversion from " << input_type
2093 << " to " << result_type;
2094 }
2095 break;
2096
Roland Levillaindff1f282014-11-05 14:15:05 +00002097 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002098 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002099 case Primitive::kPrimBoolean:
2100 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002101 case Primitive::kPrimByte:
2102 case Primitive::kPrimShort:
2103 case Primitive::kPrimInt:
2104 case Primitive::kPrimChar: {
2105 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002106 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2107 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002108 break;
2109 }
2110
Roland Levillain5b3ee562015-04-14 16:02:41 +01002111 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002112 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002113 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2114 conversion,
2115 conversion->GetDexPc(),
2116 nullptr);
Roland Levillain6d0e4832014-11-27 18:31:21 +00002117 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002118
Roland Levillaincff13742014-11-17 14:32:17 +00002119 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002120 // Processing a Dex `double-to-float' instruction.
2121 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2122 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002123 break;
2124
2125 default:
2126 LOG(FATAL) << "Unexpected type conversion from " << input_type
2127 << " to " << result_type;
2128 };
2129 break;
2130
Roland Levillaindff1f282014-11-05 14:15:05 +00002131 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002132 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002133 case Primitive::kPrimBoolean:
2134 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002135 case Primitive::kPrimByte:
2136 case Primitive::kPrimShort:
2137 case Primitive::kPrimInt:
2138 case Primitive::kPrimChar: {
2139 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002140 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002141 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2142 out.AsFpuRegisterPairLow<SRegister>());
2143 break;
2144 }
2145
Roland Levillain647b9ed2014-11-27 12:06:00 +00002146 case Primitive::kPrimLong: {
2147 // Processing a Dex `long-to-double' instruction.
2148 Register low = in.AsRegisterPairLow<Register>();
2149 Register high = in.AsRegisterPairHigh<Register>();
2150 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2151 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002152 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002153 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002154 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2155 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002156
Roland Levillain682393c2015-04-14 15:57:52 +01002157 // temp_d = int-to-double(high)
2158 __ vmovsr(temp_s, high);
2159 __ vcvtdi(temp_d, temp_s);
2160 // constant_d = k2Pow32EncodingForDouble
2161 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2162 // out_d = unsigned-to-double(low)
2163 __ vmovsr(out_s, low);
2164 __ vcvtdu(out_d, out_s);
2165 // out_d += temp_d * constant_d
2166 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002167 break;
2168 }
2169
Roland Levillaincff13742014-11-17 14:32:17 +00002170 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002171 // Processing a Dex `float-to-double' instruction.
2172 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2173 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002174 break;
2175
2176 default:
2177 LOG(FATAL) << "Unexpected type conversion from " << input_type
2178 << " to " << result_type;
2179 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002180 break;
2181
2182 default:
2183 LOG(FATAL) << "Unexpected type conversion from " << input_type
2184 << " to " << result_type;
2185 }
2186}
2187
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002188void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002189 LocationSummary* locations =
2190 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002191 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002192 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002193 locations->SetInAt(0, Location::RequiresRegister());
2194 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002195 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2196 break;
2197 }
2198
2199 case Primitive::kPrimLong: {
2200 locations->SetInAt(0, Location::RequiresRegister());
2201 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002202 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002203 break;
2204 }
2205
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002206 case Primitive::kPrimFloat:
2207 case Primitive::kPrimDouble: {
2208 locations->SetInAt(0, Location::RequiresFpuRegister());
2209 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002210 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002211 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002212 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002213
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002214 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002215 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002216 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002217}
2218
2219void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2220 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002221 Location out = locations->Out();
2222 Location first = locations->InAt(0);
2223 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002224 switch (add->GetResultType()) {
2225 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002226 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002227 __ add(out.AsRegister<Register>(),
2228 first.AsRegister<Register>(),
2229 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002230 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002231 __ AddConstant(out.AsRegister<Register>(),
2232 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002233 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002234 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002235 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002236
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002237 case Primitive::kPrimLong: {
2238 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002239 __ adds(out.AsRegisterPairLow<Register>(),
2240 first.AsRegisterPairLow<Register>(),
2241 ShifterOperand(second.AsRegisterPairLow<Register>()));
2242 __ adc(out.AsRegisterPairHigh<Register>(),
2243 first.AsRegisterPairHigh<Register>(),
2244 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002245 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002246 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002247
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002248 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002249 __ vadds(out.AsFpuRegister<SRegister>(),
2250 first.AsFpuRegister<SRegister>(),
2251 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002252 break;
2253
2254 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002255 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2256 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2257 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002258 break;
2259
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002260 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002261 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002262 }
2263}
2264
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002265void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002266 LocationSummary* locations =
2267 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002268 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002269 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002270 locations->SetInAt(0, Location::RequiresRegister());
2271 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002272 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2273 break;
2274 }
2275
2276 case Primitive::kPrimLong: {
2277 locations->SetInAt(0, Location::RequiresRegister());
2278 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002279 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002280 break;
2281 }
Calin Juravle11351682014-10-23 15:38:15 +01002282 case Primitive::kPrimFloat:
2283 case Primitive::kPrimDouble: {
2284 locations->SetInAt(0, Location::RequiresFpuRegister());
2285 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002286 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002287 break;
Calin Juravle11351682014-10-23 15:38:15 +01002288 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002289 default:
Calin Juravle11351682014-10-23 15:38:15 +01002290 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002291 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002292}
2293
2294void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2295 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002296 Location out = locations->Out();
2297 Location first = locations->InAt(0);
2298 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002299 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002300 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002301 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002302 __ sub(out.AsRegister<Register>(),
2303 first.AsRegister<Register>(),
2304 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002305 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002306 __ AddConstant(out.AsRegister<Register>(),
2307 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002308 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002309 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002310 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002311 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002312
Calin Juravle11351682014-10-23 15:38:15 +01002313 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002314 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002315 __ subs(out.AsRegisterPairLow<Register>(),
2316 first.AsRegisterPairLow<Register>(),
2317 ShifterOperand(second.AsRegisterPairLow<Register>()));
2318 __ sbc(out.AsRegisterPairHigh<Register>(),
2319 first.AsRegisterPairHigh<Register>(),
2320 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002321 break;
Calin Juravle11351682014-10-23 15:38:15 +01002322 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002323
Calin Juravle11351682014-10-23 15:38:15 +01002324 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002325 __ vsubs(out.AsFpuRegister<SRegister>(),
2326 first.AsFpuRegister<SRegister>(),
2327 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002328 break;
Calin Juravle11351682014-10-23 15:38:15 +01002329 }
2330
2331 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002332 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2333 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2334 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002335 break;
2336 }
2337
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002338
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002339 default:
Calin Juravle11351682014-10-23 15:38:15 +01002340 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002341 }
2342}
2343
Calin Juravle34bacdf2014-10-07 20:23:36 +01002344void LocationsBuilderARM::VisitMul(HMul* mul) {
2345 LocationSummary* locations =
2346 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2347 switch (mul->GetResultType()) {
2348 case Primitive::kPrimInt:
2349 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002350 locations->SetInAt(0, Location::RequiresRegister());
2351 locations->SetInAt(1, Location::RequiresRegister());
2352 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002353 break;
2354 }
2355
Calin Juravleb5bfa962014-10-21 18:02:24 +01002356 case Primitive::kPrimFloat:
2357 case Primitive::kPrimDouble: {
2358 locations->SetInAt(0, Location::RequiresFpuRegister());
2359 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002360 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002361 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002362 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002363
2364 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002365 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002366 }
2367}
2368
2369void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2370 LocationSummary* locations = mul->GetLocations();
2371 Location out = locations->Out();
2372 Location first = locations->InAt(0);
2373 Location second = locations->InAt(1);
2374 switch (mul->GetResultType()) {
2375 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002376 __ mul(out.AsRegister<Register>(),
2377 first.AsRegister<Register>(),
2378 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002379 break;
2380 }
2381 case Primitive::kPrimLong: {
2382 Register out_hi = out.AsRegisterPairHigh<Register>();
2383 Register out_lo = out.AsRegisterPairLow<Register>();
2384 Register in1_hi = first.AsRegisterPairHigh<Register>();
2385 Register in1_lo = first.AsRegisterPairLow<Register>();
2386 Register in2_hi = second.AsRegisterPairHigh<Register>();
2387 Register in2_lo = second.AsRegisterPairLow<Register>();
2388
2389 // Extra checks to protect caused by the existence of R1_R2.
2390 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2391 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2392 DCHECK_NE(out_hi, in1_lo);
2393 DCHECK_NE(out_hi, in2_lo);
2394
2395 // input: in1 - 64 bits, in2 - 64 bits
2396 // output: out
2397 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2398 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2399 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2400
2401 // IP <- in1.lo * in2.hi
2402 __ mul(IP, in1_lo, in2_hi);
2403 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2404 __ mla(out_hi, in1_hi, in2_lo, IP);
2405 // out.lo <- (in1.lo * in2.lo)[31:0];
2406 __ umull(out_lo, IP, in1_lo, in2_lo);
2407 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2408 __ add(out_hi, out_hi, ShifterOperand(IP));
2409 break;
2410 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002411
2412 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002413 __ vmuls(out.AsFpuRegister<SRegister>(),
2414 first.AsFpuRegister<SRegister>(),
2415 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002416 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002417 }
2418
2419 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002420 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2421 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2422 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002423 break;
2424 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002425
2426 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002427 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002428 }
2429}
2430
Zheng Xuc6667102015-05-15 16:08:45 +08002431void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2432 DCHECK(instruction->IsDiv() || instruction->IsRem());
2433 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2434
2435 LocationSummary* locations = instruction->GetLocations();
2436 Location second = locations->InAt(1);
2437 DCHECK(second.IsConstant());
2438
2439 Register out = locations->Out().AsRegister<Register>();
2440 Register dividend = locations->InAt(0).AsRegister<Register>();
2441 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2442 DCHECK(imm == 1 || imm == -1);
2443
2444 if (instruction->IsRem()) {
2445 __ LoadImmediate(out, 0);
2446 } else {
2447 if (imm == 1) {
2448 __ Mov(out, dividend);
2449 } else {
2450 __ rsb(out, dividend, ShifterOperand(0));
2451 }
2452 }
2453}
2454
2455void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2456 DCHECK(instruction->IsDiv() || instruction->IsRem());
2457 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2458
2459 LocationSummary* locations = instruction->GetLocations();
2460 Location second = locations->InAt(1);
2461 DCHECK(second.IsConstant());
2462
2463 Register out = locations->Out().AsRegister<Register>();
2464 Register dividend = locations->InAt(0).AsRegister<Register>();
2465 Register temp = locations->GetTemp(0).AsRegister<Register>();
2466 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Vladimir Marko80afd022015-05-19 18:08:00 +01002467 uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002468 DCHECK(IsPowerOfTwo(abs_imm));
2469 int ctz_imm = CTZ(abs_imm);
2470
2471 if (ctz_imm == 1) {
2472 __ Lsr(temp, dividend, 32 - ctz_imm);
2473 } else {
2474 __ Asr(temp, dividend, 31);
2475 __ Lsr(temp, temp, 32 - ctz_imm);
2476 }
2477 __ add(out, temp, ShifterOperand(dividend));
2478
2479 if (instruction->IsDiv()) {
2480 __ Asr(out, out, ctz_imm);
2481 if (imm < 0) {
2482 __ rsb(out, out, ShifterOperand(0));
2483 }
2484 } else {
2485 __ ubfx(out, out, 0, ctz_imm);
2486 __ sub(out, out, ShifterOperand(temp));
2487 }
2488}
2489
2490void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2491 DCHECK(instruction->IsDiv() || instruction->IsRem());
2492 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2493
2494 LocationSummary* locations = instruction->GetLocations();
2495 Location second = locations->InAt(1);
2496 DCHECK(second.IsConstant());
2497
2498 Register out = locations->Out().AsRegister<Register>();
2499 Register dividend = locations->InAt(0).AsRegister<Register>();
2500 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2501 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2502 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2503
2504 int64_t magic;
2505 int shift;
2506 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2507
2508 __ LoadImmediate(temp1, magic);
2509 __ smull(temp2, temp1, dividend, temp1);
2510
2511 if (imm > 0 && magic < 0) {
2512 __ add(temp1, temp1, ShifterOperand(dividend));
2513 } else if (imm < 0 && magic > 0) {
2514 __ sub(temp1, temp1, ShifterOperand(dividend));
2515 }
2516
2517 if (shift != 0) {
2518 __ Asr(temp1, temp1, shift);
2519 }
2520
2521 if (instruction->IsDiv()) {
2522 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2523 } else {
2524 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2525 // TODO: Strength reduction for mls.
2526 __ LoadImmediate(temp2, imm);
2527 __ mls(out, temp1, temp2, dividend);
2528 }
2529}
2530
2531void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2532 DCHECK(instruction->IsDiv() || instruction->IsRem());
2533 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2534
2535 LocationSummary* locations = instruction->GetLocations();
2536 Location second = locations->InAt(1);
2537 DCHECK(second.IsConstant());
2538
2539 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2540 if (imm == 0) {
2541 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2542 } else if (imm == 1 || imm == -1) {
2543 DivRemOneOrMinusOne(instruction);
2544 } else if (IsPowerOfTwo(std::abs(imm))) {
2545 DivRemByPowerOfTwo(instruction);
2546 } else {
2547 DCHECK(imm <= -2 || imm >= 2);
2548 GenerateDivRemWithAnyConstant(instruction);
2549 }
2550}
2551
Calin Juravle7c4954d2014-10-28 16:57:40 +00002552void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002553 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2554 if (div->GetResultType() == Primitive::kPrimLong) {
2555 // pLdiv runtime call.
2556 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002557 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2558 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002559 } else if (div->GetResultType() == Primitive::kPrimInt &&
2560 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2561 // pIdivmod runtime call.
2562 call_kind = LocationSummary::kCall;
2563 }
2564
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002565 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2566
Calin Juravle7c4954d2014-10-28 16:57:40 +00002567 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002568 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002569 if (div->InputAt(1)->IsConstant()) {
2570 locations->SetInAt(0, Location::RequiresRegister());
2571 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
2572 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2573 int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2574 if (abs_imm <= 1) {
2575 // No temp register required.
2576 } else {
2577 locations->AddTemp(Location::RequiresRegister());
2578 if (!IsPowerOfTwo(abs_imm)) {
2579 locations->AddTemp(Location::RequiresRegister());
2580 }
2581 }
2582 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002583 locations->SetInAt(0, Location::RequiresRegister());
2584 locations->SetInAt(1, Location::RequiresRegister());
2585 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2586 } else {
2587 InvokeRuntimeCallingConvention calling_convention;
2588 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2589 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2590 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2591 // we only need the former.
2592 locations->SetOut(Location::RegisterLocation(R0));
2593 }
Calin Juravled0d48522014-11-04 16:40:20 +00002594 break;
2595 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002596 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002597 InvokeRuntimeCallingConvention calling_convention;
2598 locations->SetInAt(0, Location::RegisterPairLocation(
2599 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2600 locations->SetInAt(1, Location::RegisterPairLocation(
2601 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002602 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002603 break;
2604 }
2605 case Primitive::kPrimFloat:
2606 case Primitive::kPrimDouble: {
2607 locations->SetInAt(0, Location::RequiresFpuRegister());
2608 locations->SetInAt(1, Location::RequiresFpuRegister());
2609 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2610 break;
2611 }
2612
2613 default:
2614 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2615 }
2616}
2617
2618void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2619 LocationSummary* locations = div->GetLocations();
2620 Location out = locations->Out();
2621 Location first = locations->InAt(0);
2622 Location second = locations->InAt(1);
2623
2624 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002625 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002626 if (second.IsConstant()) {
2627 GenerateDivRemConstantIntegral(div);
2628 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002629 __ sdiv(out.AsRegister<Register>(),
2630 first.AsRegister<Register>(),
2631 second.AsRegister<Register>());
2632 } else {
2633 InvokeRuntimeCallingConvention calling_convention;
2634 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2635 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2636 DCHECK_EQ(R0, out.AsRegister<Register>());
2637
2638 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2639 }
Calin Juravled0d48522014-11-04 16:40:20 +00002640 break;
2641 }
2642
Calin Juravle7c4954d2014-10-28 16:57:40 +00002643 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002644 InvokeRuntimeCallingConvention calling_convention;
2645 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2646 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2647 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2648 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2649 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002650 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002651
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002652 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002653 break;
2654 }
2655
2656 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002657 __ vdivs(out.AsFpuRegister<SRegister>(),
2658 first.AsFpuRegister<SRegister>(),
2659 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002660 break;
2661 }
2662
2663 case Primitive::kPrimDouble: {
2664 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2665 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2666 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2667 break;
2668 }
2669
2670 default:
2671 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2672 }
2673}
2674
Calin Juravlebacfec32014-11-14 15:54:36 +00002675void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002676 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002677
2678 // Most remainders are implemented in the runtime.
2679 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002680 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
2681 // sdiv will be replaced by other instruction sequence.
2682 call_kind = LocationSummary::kNoCall;
2683 } else if ((rem->GetResultType() == Primitive::kPrimInt)
2684 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002685 // Have hardware divide instruction for int, do it with three instructions.
2686 call_kind = LocationSummary::kNoCall;
2687 }
2688
Calin Juravlebacfec32014-11-14 15:54:36 +00002689 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2690
Calin Juravled2ec87d2014-12-08 14:24:46 +00002691 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002692 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002693 if (rem->InputAt(1)->IsConstant()) {
2694 locations->SetInAt(0, Location::RequiresRegister());
2695 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
2696 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2697 int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
2698 if (abs_imm <= 1) {
2699 // No temp register required.
2700 } else {
2701 locations->AddTemp(Location::RequiresRegister());
2702 if (!IsPowerOfTwo(abs_imm)) {
2703 locations->AddTemp(Location::RequiresRegister());
2704 }
2705 }
2706 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002707 locations->SetInAt(0, Location::RequiresRegister());
2708 locations->SetInAt(1, Location::RequiresRegister());
2709 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2710 locations->AddTemp(Location::RequiresRegister());
2711 } else {
2712 InvokeRuntimeCallingConvention calling_convention;
2713 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2714 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2715 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2716 // we only need the latter.
2717 locations->SetOut(Location::RegisterLocation(R1));
2718 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002719 break;
2720 }
2721 case Primitive::kPrimLong: {
2722 InvokeRuntimeCallingConvention calling_convention;
2723 locations->SetInAt(0, Location::RegisterPairLocation(
2724 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2725 locations->SetInAt(1, Location::RegisterPairLocation(
2726 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2727 // The runtime helper puts the output in R2,R3.
2728 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2729 break;
2730 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002731 case Primitive::kPrimFloat: {
2732 InvokeRuntimeCallingConvention calling_convention;
2733 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2734 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2735 locations->SetOut(Location::FpuRegisterLocation(S0));
2736 break;
2737 }
2738
Calin Juravlebacfec32014-11-14 15:54:36 +00002739 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002740 InvokeRuntimeCallingConvention calling_convention;
2741 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2742 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2743 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2744 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2745 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002746 break;
2747 }
2748
2749 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002750 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002751 }
2752}
2753
2754void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2755 LocationSummary* locations = rem->GetLocations();
2756 Location out = locations->Out();
2757 Location first = locations->InAt(0);
2758 Location second = locations->InAt(1);
2759
Calin Juravled2ec87d2014-12-08 14:24:46 +00002760 Primitive::Type type = rem->GetResultType();
2761 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002762 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002763 if (second.IsConstant()) {
2764 GenerateDivRemConstantIntegral(rem);
2765 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002766 Register reg1 = first.AsRegister<Register>();
2767 Register reg2 = second.AsRegister<Register>();
2768 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002769
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002770 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002771 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002772 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002773 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002774 } else {
2775 InvokeRuntimeCallingConvention calling_convention;
2776 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2777 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2778 DCHECK_EQ(R1, out.AsRegister<Register>());
2779
2780 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2781 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002782 break;
2783 }
2784
2785 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002786 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002787 break;
2788 }
2789
Calin Juravled2ec87d2014-12-08 14:24:46 +00002790 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002791 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002792 break;
2793 }
2794
Calin Juravlebacfec32014-11-14 15:54:36 +00002795 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002796 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002797 break;
2798 }
2799
2800 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002801 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002802 }
2803}
2804
Calin Juravled0d48522014-11-04 16:40:20 +00002805void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00002806 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
2807 ? LocationSummary::kCallOnSlowPath
2808 : LocationSummary::kNoCall;
2809 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002810 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002811 if (instruction->HasUses()) {
2812 locations->SetOut(Location::SameAsFirstInput());
2813 }
2814}
2815
2816void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07002817 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00002818 codegen_->AddSlowPath(slow_path);
2819
2820 LocationSummary* locations = instruction->GetLocations();
2821 Location value = locations->InAt(0);
2822
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002823 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06002824 case Primitive::kPrimByte:
2825 case Primitive::kPrimChar:
2826 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002827 case Primitive::kPrimInt: {
2828 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01002829 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002830 } else {
2831 DCHECK(value.IsConstant()) << value;
2832 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2833 __ b(slow_path->GetEntryLabel());
2834 }
2835 }
2836 break;
2837 }
2838 case Primitive::kPrimLong: {
2839 if (value.IsRegisterPair()) {
2840 __ orrs(IP,
2841 value.AsRegisterPairLow<Register>(),
2842 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2843 __ b(slow_path->GetEntryLabel(), EQ);
2844 } else {
2845 DCHECK(value.IsConstant()) << value;
2846 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2847 __ b(slow_path->GetEntryLabel());
2848 }
2849 }
2850 break;
2851 default:
2852 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2853 }
2854 }
Calin Juravled0d48522014-11-04 16:40:20 +00002855}
2856
Calin Juravle9aec02f2014-11-18 23:06:35 +00002857void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2858 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2859
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002860 LocationSummary* locations =
2861 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002862
2863 switch (op->GetResultType()) {
2864 case Primitive::kPrimInt: {
2865 locations->SetInAt(0, Location::RequiresRegister());
2866 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002867 // Make the output overlap, as it will be used to hold the masked
2868 // second input.
2869 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002870 break;
2871 }
2872 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002873 locations->SetInAt(0, Location::RequiresRegister());
2874 locations->SetInAt(1, Location::RequiresRegister());
2875 locations->AddTemp(Location::RequiresRegister());
2876 locations->SetOut(Location::RequiresRegister());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002877 break;
2878 }
2879 default:
2880 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2881 }
2882}
2883
2884void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2885 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2886
2887 LocationSummary* locations = op->GetLocations();
2888 Location out = locations->Out();
2889 Location first = locations->InAt(0);
2890 Location second = locations->InAt(1);
2891
2892 Primitive::Type type = op->GetResultType();
2893 switch (type) {
2894 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002895 Register out_reg = out.AsRegister<Register>();
2896 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002897 // Arm doesn't mask the shift count so we need to do it ourselves.
2898 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002899 Register second_reg = second.AsRegister<Register>();
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002900 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
Calin Juravle9aec02f2014-11-18 23:06:35 +00002901 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002902 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002903 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002904 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002905 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002906 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002907 }
2908 } else {
2909 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2910 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2911 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2912 __ Mov(out_reg, first_reg);
2913 } else if (op->IsShl()) {
2914 __ Lsl(out_reg, first_reg, shift_value);
2915 } else if (op->IsShr()) {
2916 __ Asr(out_reg, first_reg, shift_value);
2917 } else {
2918 __ Lsr(out_reg, first_reg, shift_value);
2919 }
2920 }
2921 break;
2922 }
2923 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002924 Register o_h = out.AsRegisterPairHigh<Register>();
2925 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002926
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002927 Register temp = locations->GetTemp(0).AsRegister<Register>();
2928
2929 Register high = first.AsRegisterPairHigh<Register>();
2930 Register low = first.AsRegisterPairLow<Register>();
2931
2932 Register second_reg = second.AsRegister<Register>();
2933
Calin Juravle9aec02f2014-11-18 23:06:35 +00002934 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002935 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002936 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002937 __ Lsl(o_h, high, o_l);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002938 // Shift the low part and `or` what overflew on the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002939 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002940 __ Lsr(temp, low, temp);
2941 __ orr(o_h, o_h, ShifterOperand(temp));
2942 // If the shift is > 32 bits, override the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002943 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002944 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002945 __ Lsl(o_h, low, temp, PL);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002946 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002947 __ Lsl(o_l, low, o_l);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002948 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002949 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002950 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002951 __ Lsr(o_l, low, o_h);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002952 // Shift the high part and `or` what underflew on the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002953 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002954 __ Lsl(temp, high, temp);
2955 __ orr(o_l, o_l, ShifterOperand(temp));
2956 // If the shift is > 32 bits, override the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002957 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002958 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002959 __ Asr(o_l, high, temp, PL);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002960 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002961 __ Asr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002962 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002963 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002964 // same as Shr except we use `Lsr`s and not `Asr`s
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002965 __ Lsr(o_l, low, o_h);
2966 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002967 __ Lsl(temp, high, temp);
2968 __ orr(o_l, o_l, ShifterOperand(temp));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002969 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002970 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002971 __ Lsr(o_l, high, temp, PL);
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002972 __ Lsr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002973 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00002974 break;
2975 }
2976 default:
2977 LOG(FATAL) << "Unexpected operation type " << type;
2978 }
2979}
2980
2981void LocationsBuilderARM::VisitShl(HShl* shl) {
2982 HandleShift(shl);
2983}
2984
2985void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
2986 HandleShift(shl);
2987}
2988
2989void LocationsBuilderARM::VisitShr(HShr* shr) {
2990 HandleShift(shr);
2991}
2992
2993void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
2994 HandleShift(shr);
2995}
2996
2997void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
2998 HandleShift(ushr);
2999}
3000
3001void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3002 HandleShift(ushr);
3003}
3004
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003005void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003006 LocationSummary* locations =
3007 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003008 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003009 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003010 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003011 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003012}
3013
3014void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
3015 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003016 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003017 // Note: if heap poisoning is enabled, the entry point takes cares
3018 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003019 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003020 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003021 instruction->GetDexPc(),
3022 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003023}
3024
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003025void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3026 LocationSummary* locations =
3027 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3028 InvokeRuntimeCallingConvention calling_convention;
3029 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003030 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003031 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003032 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003033}
3034
3035void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3036 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003037 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003038 // Note: if heap poisoning is enabled, the entry point takes cares
3039 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003040 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003041 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003042 instruction->GetDexPc(),
3043 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003044}
3045
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003046void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003047 LocationSummary* locations =
3048 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003049 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3050 if (location.IsStackSlot()) {
3051 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3052 } else if (location.IsDoubleStackSlot()) {
3053 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003054 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003055 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003056}
3057
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003058void InstructionCodeGeneratorARM::VisitParameterValue(
3059 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003060 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003061}
3062
3063void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3064 LocationSummary* locations =
3065 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3066 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3067}
3068
3069void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3070 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003071}
3072
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003073void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003074 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003075 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003076 locations->SetInAt(0, Location::RequiresRegister());
3077 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003078}
3079
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003080void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3081 LocationSummary* locations = not_->GetLocations();
3082 Location out = locations->Out();
3083 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003084 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003085 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003086 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003087 break;
3088
3089 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003090 __ mvn(out.AsRegisterPairLow<Register>(),
3091 ShifterOperand(in.AsRegisterPairLow<Register>()));
3092 __ mvn(out.AsRegisterPairHigh<Register>(),
3093 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003094 break;
3095
3096 default:
3097 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3098 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003099}
3100
David Brazdil66d126e2015-04-03 16:02:44 +01003101void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3102 LocationSummary* locations =
3103 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3104 locations->SetInAt(0, Location::RequiresRegister());
3105 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3106}
3107
3108void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003109 LocationSummary* locations = bool_not->GetLocations();
3110 Location out = locations->Out();
3111 Location in = locations->InAt(0);
3112 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3113}
3114
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003115void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003116 LocationSummary* locations =
3117 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003118 switch (compare->InputAt(0)->GetType()) {
3119 case Primitive::kPrimLong: {
3120 locations->SetInAt(0, Location::RequiresRegister());
3121 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003122 // Output overlaps because it is written before doing the low comparison.
3123 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003124 break;
3125 }
3126 case Primitive::kPrimFloat:
3127 case Primitive::kPrimDouble: {
3128 locations->SetInAt(0, Location::RequiresFpuRegister());
3129 locations->SetInAt(1, Location::RequiresFpuRegister());
3130 locations->SetOut(Location::RequiresRegister());
3131 break;
3132 }
3133 default:
3134 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3135 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003136}
3137
3138void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003139 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003140 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003141 Location left = locations->InAt(0);
3142 Location right = locations->InAt(1);
3143
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003144 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003145 Primitive::Type type = compare->InputAt(0)->GetType();
3146 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003147 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003148 __ cmp(left.AsRegisterPairHigh<Register>(),
3149 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003150 __ b(&less, LT);
3151 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003152 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003153 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003154 __ cmp(left.AsRegisterPairLow<Register>(),
3155 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00003156 break;
3157 }
3158 case Primitive::kPrimFloat:
3159 case Primitive::kPrimDouble: {
3160 __ LoadImmediate(out, 0);
3161 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003162 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003163 } else {
3164 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3165 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3166 }
3167 __ vmstat(); // transfer FP status register to ARM APSR.
3168 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003169 break;
3170 }
3171 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003172 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003173 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003174 __ b(&done, EQ);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003175 __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats.
Calin Juravleddb7df22014-11-25 20:56:51 +00003176
3177 __ Bind(&greater);
3178 __ LoadImmediate(out, 1);
3179 __ b(&done);
3180
3181 __ Bind(&less);
3182 __ LoadImmediate(out, -1);
3183
3184 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003185}
3186
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003187void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003188 LocationSummary* locations =
3189 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003190 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3191 locations->SetInAt(i, Location::Any());
3192 }
3193 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003194}
3195
3196void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003197 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003198 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003199}
3200
Calin Juravle52c48962014-12-16 17:02:57 +00003201void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3202 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07003203 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00003204 switch (kind) {
3205 case MemBarrierKind::kAnyStore:
3206 case MemBarrierKind::kLoadAny:
3207 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003208 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003209 break;
3210 }
3211 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003212 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003213 break;
3214 }
3215 default:
3216 LOG(FATAL) << "Unexpected memory barrier " << kind;
3217 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003218 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003219}
3220
3221void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3222 uint32_t offset,
3223 Register out_lo,
3224 Register out_hi) {
3225 if (offset != 0) {
3226 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003227 __ add(IP, addr, ShifterOperand(out_lo));
3228 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003229 }
3230 __ ldrexd(out_lo, out_hi, addr);
3231}
3232
3233void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3234 uint32_t offset,
3235 Register value_lo,
3236 Register value_hi,
3237 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003238 Register temp2,
3239 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003240 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003241 if (offset != 0) {
3242 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003243 __ add(IP, addr, ShifterOperand(temp1));
3244 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003245 }
3246 __ Bind(&fail);
3247 // We need a load followed by store. (The address used in a STREX instruction must
3248 // be the same as the address in the most recently executed LDREX instruction.)
3249 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003250 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003251 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003252 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003253}
3254
3255void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3256 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3257
Nicolas Geoffray39468442014-09-02 15:17:15 +01003258 LocationSummary* locations =
3259 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003260 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003261
Calin Juravle52c48962014-12-16 17:02:57 +00003262 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003263 if (Primitive::IsFloatingPointType(field_type)) {
3264 locations->SetInAt(1, Location::RequiresFpuRegister());
3265 } else {
3266 locations->SetInAt(1, Location::RequiresRegister());
3267 }
3268
Calin Juravle52c48962014-12-16 17:02:57 +00003269 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003270 bool generate_volatile = field_info.IsVolatile()
3271 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003272 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003273 bool needs_write_barrier =
3274 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003275 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003276 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003277 if (needs_write_barrier) {
3278 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003279 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003280 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00003281 // Arm encoding have some additional constraints for ldrexd/strexd:
3282 // - registers need to be consecutive
3283 // - the first register should be even but not R14.
3284 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3285 // enable Arm encoding.
3286 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3287
3288 locations->AddTemp(Location::RequiresRegister());
3289 locations->AddTemp(Location::RequiresRegister());
3290 if (field_type == Primitive::kPrimDouble) {
3291 // For doubles we need two more registers to copy the value.
3292 locations->AddTemp(Location::RegisterLocation(R2));
3293 locations->AddTemp(Location::RegisterLocation(R3));
3294 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003295 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003296}
3297
Calin Juravle52c48962014-12-16 17:02:57 +00003298void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003299 const FieldInfo& field_info,
3300 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003301 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3302
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003303 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003304 Register base = locations->InAt(0).AsRegister<Register>();
3305 Location value = locations->InAt(1);
3306
3307 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003308 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003309 Primitive::Type field_type = field_info.GetFieldType();
3310 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003311 bool needs_write_barrier =
3312 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003313
3314 if (is_volatile) {
3315 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3316 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003317
3318 switch (field_type) {
3319 case Primitive::kPrimBoolean:
3320 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003321 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003322 break;
3323 }
3324
3325 case Primitive::kPrimShort:
3326 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003327 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003328 break;
3329 }
3330
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003331 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003332 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003333 if (kPoisonHeapReferences && needs_write_barrier) {
3334 // Note that in the case where `value` is a null reference,
3335 // we do not enter this block, as a null reference does not
3336 // need poisoning.
3337 DCHECK_EQ(field_type, Primitive::kPrimNot);
3338 Register temp = locations->GetTemp(0).AsRegister<Register>();
3339 __ Mov(temp, value.AsRegister<Register>());
3340 __ PoisonHeapReference(temp);
3341 __ StoreToOffset(kStoreWord, temp, base, offset);
3342 } else {
3343 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3344 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003345 break;
3346 }
3347
3348 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003349 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003350 GenerateWideAtomicStore(base, offset,
3351 value.AsRegisterPairLow<Register>(),
3352 value.AsRegisterPairHigh<Register>(),
3353 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003354 locations->GetTemp(1).AsRegister<Register>(),
3355 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003356 } else {
3357 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003358 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003359 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003360 break;
3361 }
3362
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003363 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003364 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003365 break;
3366 }
3367
3368 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003369 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003370 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003371 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3372 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3373
3374 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3375
3376 GenerateWideAtomicStore(base, offset,
3377 value_reg_lo,
3378 value_reg_hi,
3379 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003380 locations->GetTemp(3).AsRegister<Register>(),
3381 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003382 } else {
3383 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003384 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003385 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003386 break;
3387 }
3388
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003389 case Primitive::kPrimVoid:
3390 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003391 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003392 }
Calin Juravle52c48962014-12-16 17:02:57 +00003393
Calin Juravle77520bc2015-01-12 18:45:46 +00003394 // Longs and doubles are handled in the switch.
3395 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3396 codegen_->MaybeRecordImplicitNullCheck(instruction);
3397 }
3398
3399 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3400 Register temp = locations->GetTemp(0).AsRegister<Register>();
3401 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003402 codegen_->MarkGCCard(
3403 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003404 }
3405
Calin Juravle52c48962014-12-16 17:02:57 +00003406 if (is_volatile) {
3407 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3408 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003409}
3410
Calin Juravle52c48962014-12-16 17:02:57 +00003411void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3412 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003413 LocationSummary* locations =
3414 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003415 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003416
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003417 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003418 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003419 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003420 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003421
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003422 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3423 locations->SetOut(Location::RequiresFpuRegister());
3424 } else {
3425 locations->SetOut(Location::RequiresRegister(),
3426 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3427 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003428 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00003429 // Arm encoding have some additional constraints for ldrexd/strexd:
3430 // - registers need to be consecutive
3431 // - the first register should be even but not R14.
3432 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3433 // enable Arm encoding.
3434 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3435 locations->AddTemp(Location::RequiresRegister());
3436 locations->AddTemp(Location::RequiresRegister());
3437 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003438}
3439
Calin Juravle52c48962014-12-16 17:02:57 +00003440void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
3441 const FieldInfo& field_info) {
3442 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003443
Calin Juravle52c48962014-12-16 17:02:57 +00003444 LocationSummary* locations = instruction->GetLocations();
3445 Register base = locations->InAt(0).AsRegister<Register>();
3446 Location out = locations->Out();
3447 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003448 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003449 Primitive::Type field_type = field_info.GetFieldType();
3450 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3451
3452 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003453 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003454 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003455 break;
3456 }
3457
3458 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003459 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003460 break;
3461 }
3462
3463 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003464 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003465 break;
3466 }
3467
3468 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003469 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003470 break;
3471 }
3472
3473 case Primitive::kPrimInt:
3474 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003475 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003476 break;
3477 }
3478
3479 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003480 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003481 GenerateWideAtomicLoad(base, offset,
3482 out.AsRegisterPairLow<Register>(),
3483 out.AsRegisterPairHigh<Register>());
3484 } else {
3485 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3486 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003487 break;
3488 }
3489
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003490 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003491 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003492 break;
3493 }
3494
3495 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003496 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003497 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003498 Register lo = locations->GetTemp(0).AsRegister<Register>();
3499 Register hi = locations->GetTemp(1).AsRegister<Register>();
3500 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003501 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003502 __ vmovdrr(out_reg, lo, hi);
3503 } else {
3504 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003505 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003506 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003507 break;
3508 }
3509
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003510 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003511 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003512 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003513 }
Calin Juravle52c48962014-12-16 17:02:57 +00003514
Calin Juravle77520bc2015-01-12 18:45:46 +00003515 // Doubles are handled in the switch.
3516 if (field_type != Primitive::kPrimDouble) {
3517 codegen_->MaybeRecordImplicitNullCheck(instruction);
3518 }
3519
Calin Juravle52c48962014-12-16 17:02:57 +00003520 if (is_volatile) {
3521 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3522 }
Roland Levillain4d027112015-07-01 15:41:14 +01003523
3524 if (field_type == Primitive::kPrimNot) {
3525 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3526 }
Calin Juravle52c48962014-12-16 17:02:57 +00003527}
3528
3529void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3530 HandleFieldSet(instruction, instruction->GetFieldInfo());
3531}
3532
3533void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003534 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003535}
3536
3537void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3538 HandleFieldGet(instruction, instruction->GetFieldInfo());
3539}
3540
3541void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3542 HandleFieldGet(instruction, instruction->GetFieldInfo());
3543}
3544
3545void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3546 HandleFieldGet(instruction, instruction->GetFieldInfo());
3547}
3548
3549void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3550 HandleFieldGet(instruction, instruction->GetFieldInfo());
3551}
3552
3553void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3554 HandleFieldSet(instruction, instruction->GetFieldInfo());
3555}
3556
3557void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003558 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003559}
3560
3561void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003562 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3563 ? LocationSummary::kCallOnSlowPath
3564 : LocationSummary::kNoCall;
3565 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00003566 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003567 if (instruction->HasUses()) {
3568 locations->SetOut(Location::SameAsFirstInput());
3569 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003570}
3571
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003572void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003573 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3574 return;
3575 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003576 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003577
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003578 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3579 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3580}
3581
3582void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003583 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003584 codegen_->AddSlowPath(slow_path);
3585
3586 LocationSummary* locations = instruction->GetLocations();
3587 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003588
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003589 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003590}
3591
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003592void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003593 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003594 GenerateImplicitNullCheck(instruction);
3595 } else {
3596 GenerateExplicitNullCheck(instruction);
3597 }
3598}
3599
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003600void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003601 LocationSummary* locations =
3602 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003603 locations->SetInAt(0, Location::RequiresRegister());
3604 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003605 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3606 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3607 } else {
3608 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3609 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003610}
3611
3612void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3613 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003614 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003615 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003616 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003617
Roland Levillain4d027112015-07-01 15:41:14 +01003618 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003619 case Primitive::kPrimBoolean: {
3620 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003621 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003622 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003623 size_t offset =
3624 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003625 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3626 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003627 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003628 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3629 }
3630 break;
3631 }
3632
3633 case Primitive::kPrimByte: {
3634 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003635 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003636 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003637 size_t offset =
3638 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003639 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3640 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003641 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003642 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3643 }
3644 break;
3645 }
3646
3647 case Primitive::kPrimShort: {
3648 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003649 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003650 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003651 size_t offset =
3652 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003653 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3654 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003655 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003656 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3657 }
3658 break;
3659 }
3660
3661 case Primitive::kPrimChar: {
3662 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003663 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003664 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003665 size_t offset =
3666 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003667 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3668 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003669 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003670 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3671 }
3672 break;
3673 }
3674
3675 case Primitive::kPrimInt:
3676 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003677 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3678 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003679 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003680 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003681 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003682 size_t offset =
3683 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003684 __ LoadFromOffset(kLoadWord, out, obj, offset);
3685 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003686 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003687 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3688 }
3689 break;
3690 }
3691
3692 case Primitive::kPrimLong: {
3693 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003694 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003695 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003696 size_t offset =
3697 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003698 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003699 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003700 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003701 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003702 }
3703 break;
3704 }
3705
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003706 case Primitive::kPrimFloat: {
3707 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3708 Location out = locations->Out();
3709 DCHECK(out.IsFpuRegister());
3710 if (index.IsConstant()) {
3711 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3712 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3713 } else {
3714 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3715 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3716 }
3717 break;
3718 }
3719
3720 case Primitive::kPrimDouble: {
3721 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3722 Location out = locations->Out();
3723 DCHECK(out.IsFpuRegisterPair());
3724 if (index.IsConstant()) {
3725 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3726 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3727 } else {
3728 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3729 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3730 }
3731 break;
3732 }
3733
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003734 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003735 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003736 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003737 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003738 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003739
3740 if (type == Primitive::kPrimNot) {
3741 Register out = locations->Out().AsRegister<Register>();
3742 __ MaybeUnpoisonHeapReference(out);
3743 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003744}
3745
3746void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003747 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003748
3749 bool needs_write_barrier =
3750 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3751 bool needs_runtime_call = instruction->NeedsTypeCheck();
3752
Nicolas Geoffray39468442014-09-02 15:17:15 +01003753 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003754 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3755 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003756 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003757 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3758 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3759 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003760 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003761 locations->SetInAt(0, Location::RequiresRegister());
3762 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003763 if (Primitive::IsFloatingPointType(value_type)) {
3764 locations->SetInAt(2, Location::RequiresFpuRegister());
3765 } else {
3766 locations->SetInAt(2, Location::RequiresRegister());
3767 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003768
3769 if (needs_write_barrier) {
3770 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003771 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003772 locations->AddTemp(Location::RequiresRegister());
3773 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003774 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003775}
3776
3777void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3778 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003779 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003780 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003781 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003782 bool needs_runtime_call = locations->WillCall();
3783 bool needs_write_barrier =
3784 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003785
3786 switch (value_type) {
3787 case Primitive::kPrimBoolean:
3788 case Primitive::kPrimByte: {
3789 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003790 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003791 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003792 size_t offset =
3793 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003794 __ StoreToOffset(kStoreByte, value, obj, offset);
3795 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003796 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003797 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3798 }
3799 break;
3800 }
3801
3802 case Primitive::kPrimShort:
3803 case Primitive::kPrimChar: {
3804 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003805 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003806 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003807 size_t offset =
3808 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003809 __ StoreToOffset(kStoreHalfword, value, obj, offset);
3810 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003811 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003812 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3813 }
3814 break;
3815 }
3816
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003817 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003818 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003819 if (!needs_runtime_call) {
3820 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003821 Register value = locations->InAt(2).AsRegister<Register>();
Roland Levillain4d027112015-07-01 15:41:14 +01003822 Register source = value;
3823 if (kPoisonHeapReferences && needs_write_barrier) {
3824 // Note that in the case where `value` is a null reference,
3825 // we do not enter this block, as a null reference does not
3826 // need poisoning.
3827 DCHECK_EQ(value_type, Primitive::kPrimNot);
3828 Register temp = locations->GetTemp(0).AsRegister<Register>();
3829 __ Mov(temp, value);
3830 __ PoisonHeapReference(temp);
3831 source = temp;
3832 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003833 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003834 size_t offset =
3835 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillain4d027112015-07-01 15:41:14 +01003836 __ StoreToOffset(kStoreWord, source, obj, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003837 } else {
3838 DCHECK(index.IsRegister()) << index;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003839 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01003840 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003841 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003842 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003843 if (needs_write_barrier) {
3844 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003845 Register temp = locations->GetTemp(0).AsRegister<Register>();
3846 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003847 codegen_->MarkGCCard(temp, card, obj, value, instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003848 }
3849 } else {
3850 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01003851 // Note: if heap poisoning is enabled, pAputObject takes cares
3852 // of poisoning the reference.
Roland Levillain199f3362014-11-27 17:15:16 +00003853 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
3854 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003855 instruction->GetDexPc(),
3856 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003857 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003858 break;
3859 }
3860
3861 case Primitive::kPrimLong: {
3862 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003863 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003864 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003865 size_t offset =
3866 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003867 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003868 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003869 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003870 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003871 }
3872 break;
3873 }
3874
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003875 case Primitive::kPrimFloat: {
3876 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3877 Location value = locations->InAt(2);
3878 DCHECK(value.IsFpuRegister());
3879 if (index.IsConstant()) {
3880 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3881 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
3882 } else {
3883 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3884 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
3885 }
3886 break;
3887 }
3888
3889 case Primitive::kPrimDouble: {
3890 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3891 Location value = locations->InAt(2);
3892 DCHECK(value.IsFpuRegisterPair());
3893 if (index.IsConstant()) {
3894 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3895 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3896 } else {
3897 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3898 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3899 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003900
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003901 break;
3902 }
3903
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003904 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003905 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003906 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003907 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003908
3909 // Ints and objects are handled in the switch.
3910 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
3911 codegen_->MaybeRecordImplicitNullCheck(instruction);
3912 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003913}
3914
3915void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003916 LocationSummary* locations =
3917 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003918 locations->SetInAt(0, Location::RequiresRegister());
3919 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003920}
3921
3922void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
3923 LocationSummary* locations = instruction->GetLocations();
3924 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003925 Register obj = locations->InAt(0).AsRegister<Register>();
3926 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003927 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003928 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003929}
3930
3931void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003932 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3933 ? LocationSummary::kCallOnSlowPath
3934 : LocationSummary::kNoCall;
3935 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003936 locations->SetInAt(0, Location::RequiresRegister());
3937 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003938 if (instruction->HasUses()) {
3939 locations->SetOut(Location::SameAsFirstInput());
3940 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003941}
3942
3943void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3944 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07003945 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01003946 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003947 codegen_->AddSlowPath(slow_path);
3948
Roland Levillain271ab9c2014-11-27 15:23:57 +00003949 Register index = locations->InAt(0).AsRegister<Register>();
3950 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003951
3952 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01003953 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003954}
3955
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003956void CodeGeneratorARM::MarkGCCard(Register temp,
3957 Register card,
3958 Register object,
3959 Register value,
3960 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003961 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003962 if (can_be_null) {
3963 __ CompareAndBranchIfZero(value, &is_null);
3964 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003965 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
3966 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
3967 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003968 if (can_be_null) {
3969 __ Bind(&is_null);
3970 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003971}
3972
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003973void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
3974 temp->SetLocations(nullptr);
3975}
3976
3977void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
3978 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003979 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003980}
3981
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003982void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003983 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003984 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003985}
3986
3987void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003988 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3989}
3990
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003991void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3992 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3993}
3994
3995void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003996 HBasicBlock* block = instruction->GetBlock();
3997 if (block->GetLoopInformation() != nullptr) {
3998 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3999 // The back edge will generate the suspend check.
4000 return;
4001 }
4002 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4003 // The goto will generate the suspend check.
4004 return;
4005 }
4006 GenerateSuspendCheck(instruction, nullptr);
4007}
4008
4009void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4010 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004011 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004012 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4013 if (slow_path == nullptr) {
4014 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4015 instruction->SetSlowPath(slow_path);
4016 codegen_->AddSlowPath(slow_path);
4017 if (successor != nullptr) {
4018 DCHECK(successor->IsLoopHeader());
4019 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4020 }
4021 } else {
4022 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4023 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004024
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004025 __ LoadFromOffset(
4026 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004027 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004028 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004029 __ Bind(slow_path->GetReturnLabel());
4030 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004031 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004032 __ b(slow_path->GetEntryLabel());
4033 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004034}
4035
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004036ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4037 return codegen_->GetAssembler();
4038}
4039
4040void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004041 DCHECK_LT(index, moves_.size());
4042 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004043 Location source = move->GetSource();
4044 Location destination = move->GetDestination();
4045
4046 if (source.IsRegister()) {
4047 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004048 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004049 } else {
4050 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004051 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004052 SP, destination.GetStackIndex());
4053 }
4054 } else if (source.IsStackSlot()) {
4055 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004056 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004057 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004058 } else if (destination.IsFpuRegister()) {
4059 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004060 } else {
4061 DCHECK(destination.IsStackSlot());
4062 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4063 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4064 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004065 } else if (source.IsFpuRegister()) {
4066 if (destination.IsFpuRegister()) {
4067 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004068 } else {
4069 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004070 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4071 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004072 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004073 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004074 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4075 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004076 } else if (destination.IsRegisterPair()) {
4077 DCHECK(ExpectedPairLayout(destination));
4078 __ LoadFromOffset(
4079 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4080 } else {
4081 DCHECK(destination.IsFpuRegisterPair()) << destination;
4082 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4083 SP,
4084 source.GetStackIndex());
4085 }
4086 } else if (source.IsRegisterPair()) {
4087 if (destination.IsRegisterPair()) {
4088 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4089 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4090 } else {
4091 DCHECK(destination.IsDoubleStackSlot()) << destination;
4092 DCHECK(ExpectedPairLayout(source));
4093 __ StoreToOffset(
4094 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4095 }
4096 } else if (source.IsFpuRegisterPair()) {
4097 if (destination.IsFpuRegisterPair()) {
4098 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4099 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4100 } else {
4101 DCHECK(destination.IsDoubleStackSlot()) << destination;
4102 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4103 SP,
4104 destination.GetStackIndex());
4105 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004106 } else {
4107 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004108 HConstant* constant = source.GetConstant();
4109 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4110 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004111 if (destination.IsRegister()) {
4112 __ LoadImmediate(destination.AsRegister<Register>(), value);
4113 } else {
4114 DCHECK(destination.IsStackSlot());
4115 __ LoadImmediate(IP, value);
4116 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4117 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004118 } else if (constant->IsLongConstant()) {
4119 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004120 if (destination.IsRegisterPair()) {
4121 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4122 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004123 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004124 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004125 __ LoadImmediate(IP, Low32Bits(value));
4126 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4127 __ LoadImmediate(IP, High32Bits(value));
4128 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4129 }
4130 } else if (constant->IsDoubleConstant()) {
4131 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004132 if (destination.IsFpuRegisterPair()) {
4133 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004134 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004135 DCHECK(destination.IsDoubleStackSlot()) << destination;
4136 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004137 __ LoadImmediate(IP, Low32Bits(int_value));
4138 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4139 __ LoadImmediate(IP, High32Bits(int_value));
4140 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4141 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004142 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004143 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004144 float value = constant->AsFloatConstant()->GetValue();
4145 if (destination.IsFpuRegister()) {
4146 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4147 } else {
4148 DCHECK(destination.IsStackSlot());
4149 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4150 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4151 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004152 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004153 }
4154}
4155
4156void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4157 __ Mov(IP, reg);
4158 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4159 __ StoreToOffset(kStoreWord, IP, SP, mem);
4160}
4161
4162void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4163 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4164 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4165 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4166 SP, mem1 + stack_offset);
4167 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4168 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4169 SP, mem2 + stack_offset);
4170 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
4171}
4172
4173void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004174 DCHECK_LT(index, moves_.size());
4175 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004176 Location source = move->GetSource();
4177 Location destination = move->GetDestination();
4178
4179 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004180 DCHECK_NE(source.AsRegister<Register>(), IP);
4181 DCHECK_NE(destination.AsRegister<Register>(), IP);
4182 __ Mov(IP, source.AsRegister<Register>());
4183 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
4184 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004185 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004186 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004187 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004188 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004189 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4190 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004191 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004192 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004193 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004194 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004195 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004196 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004197 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004198 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004199 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4200 destination.AsRegisterPairHigh<Register>(),
4201 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004202 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004203 Register low_reg = source.IsRegisterPair()
4204 ? source.AsRegisterPairLow<Register>()
4205 : destination.AsRegisterPairLow<Register>();
4206 int mem = source.IsRegisterPair()
4207 ? destination.GetStackIndex()
4208 : source.GetStackIndex();
4209 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004210 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004211 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004212 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004213 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004214 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
4215 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004216 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004217 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004218 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004219 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
4220 DRegister reg = source.IsFpuRegisterPair()
4221 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
4222 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
4223 int mem = source.IsFpuRegisterPair()
4224 ? destination.GetStackIndex()
4225 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004226 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004227 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004228 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004229 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
4230 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
4231 : destination.AsFpuRegister<SRegister>();
4232 int mem = source.IsFpuRegister()
4233 ? destination.GetStackIndex()
4234 : source.GetStackIndex();
4235
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004236 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004237 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004238 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004239 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004240 Exchange(source.GetStackIndex(), destination.GetStackIndex());
4241 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004242 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004243 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004244 }
4245}
4246
4247void ParallelMoveResolverARM::SpillScratch(int reg) {
4248 __ Push(static_cast<Register>(reg));
4249}
4250
4251void ParallelMoveResolverARM::RestoreScratch(int reg) {
4252 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004253}
4254
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004255void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004256 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4257 ? LocationSummary::kCallOnSlowPath
4258 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004259 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004260 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004261 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004262 locations->SetOut(Location::RequiresRegister());
4263}
4264
4265void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004266 LocationSummary* locations = cls->GetLocations();
4267 Register out = locations->Out().AsRegister<Register>();
4268 Register current_method = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004269 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004270 DCHECK(!cls->CanCallRuntime());
4271 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004272 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004273 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004274 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004275 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004276 __ LoadFromOffset(kLoadWord,
4277 out,
4278 current_method,
Vladimir Marko05792b92015-08-03 11:56:49 +01004279 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004280 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004281 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004282
Andreas Gampe85b62f22015-09-09 13:15:38 -07004283 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004284 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4285 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004286 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004287 if (cls->MustGenerateClinitCheck()) {
4288 GenerateClassInitializationCheck(slow_path, out);
4289 } else {
4290 __ Bind(slow_path->GetExitLabel());
4291 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004292 }
4293}
4294
4295void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
4296 LocationSummary* locations =
4297 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4298 locations->SetInAt(0, Location::RequiresRegister());
4299 if (check->HasUses()) {
4300 locations->SetOut(Location::SameAsFirstInput());
4301 }
4302}
4303
4304void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004305 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07004306 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004307 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004308 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004309 GenerateClassInitializationCheck(slow_path,
4310 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004311}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004312
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004313void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07004314 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004315 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
4316 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
4317 __ b(slow_path->GetEntryLabel(), LT);
4318 // Even if the initialized flag is set, we may be in a situation where caches are not synced
4319 // properly. Therefore, we do a memory fence.
4320 __ dmb(ISH);
4321 __ Bind(slow_path->GetExitLabel());
4322}
4323
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004324void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
4325 LocationSummary* locations =
4326 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004327 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004328 locations->SetOut(Location::RequiresRegister());
4329}
4330
4331void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004332 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004333 codegen_->AddSlowPath(slow_path);
4334
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004335 LocationSummary* locations = load->GetLocations();
4336 Register out = locations->Out().AsRegister<Register>();
4337 Register current_method = locations->InAt(0).AsRegister<Register>();
4338 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004339 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Mathieu Chartiereace4582014-11-24 18:29:54 -08004340 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004341 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004342 // TODO: We will need a read barrier here.
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004343 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004344 __ Bind(slow_path->GetExitLabel());
4345}
4346
David Brazdilcb1c0552015-08-04 16:22:25 +01004347static int32_t GetExceptionTlsOffset() {
4348 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
4349}
4350
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004351void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
4352 LocationSummary* locations =
4353 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4354 locations->SetOut(Location::RequiresRegister());
4355}
4356
4357void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004358 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01004359 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
4360}
4361
4362void LocationsBuilderARM::VisitClearException(HClearException* clear) {
4363 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4364}
4365
4366void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004367 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01004368 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004369}
4370
4371void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
4372 LocationSummary* locations =
4373 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4374 InvokeRuntimeCallingConvention calling_convention;
4375 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4376}
4377
4378void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
4379 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004380 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004381}
4382
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004383void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004384 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4385 switch (instruction->GetTypeCheckKind()) {
4386 case TypeCheckKind::kExactCheck:
4387 case TypeCheckKind::kAbstractClassCheck:
4388 case TypeCheckKind::kClassHierarchyCheck:
4389 case TypeCheckKind::kArrayObjectCheck:
4390 call_kind = LocationSummary::kNoCall;
4391 break;
4392 case TypeCheckKind::kInterfaceCheck:
4393 call_kind = LocationSummary::kCall;
4394 break;
4395 case TypeCheckKind::kArrayCheck:
4396 call_kind = LocationSummary::kCallOnSlowPath;
4397 break;
4398 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004399 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004400 if (call_kind != LocationSummary::kCall) {
4401 locations->SetInAt(0, Location::RequiresRegister());
4402 locations->SetInAt(1, Location::RequiresRegister());
4403 // The out register is used as a temporary, so it overlaps with the inputs.
4404 // Note that TypeCheckSlowPathARM uses this register too.
4405 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4406 } else {
4407 InvokeRuntimeCallingConvention calling_convention;
4408 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4409 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4410 locations->SetOut(Location::RegisterLocation(R0));
4411 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004412}
4413
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004414void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004415 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004416 Register obj = locations->InAt(0).AsRegister<Register>();
4417 Register cls = locations->InAt(1).AsRegister<Register>();
4418 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004419 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004420 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4421 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4422 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004423 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07004424 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004425
4426 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004427 // avoid null check if we know obj is not null.
4428 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00004429 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004430 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004431
4432 // In case of an interface check, we put the object class into the object register.
4433 // This is safe, as the register is caller-save, and the object must be in another
4434 // register if it survives the runtime call.
4435 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck)
4436 ? obj
4437 : out;
4438 __ LoadFromOffset(kLoadWord, target, obj, class_offset);
4439 __ MaybeUnpoisonHeapReference(target);
4440
4441 switch (instruction->GetTypeCheckKind()) {
4442 case TypeCheckKind::kExactCheck: {
4443 __ cmp(out, ShifterOperand(cls));
4444 // Classes must be equal for the instanceof to succeed.
4445 __ b(&zero, NE);
4446 __ LoadImmediate(out, 1);
4447 __ b(&done);
4448 break;
4449 }
4450 case TypeCheckKind::kAbstractClassCheck: {
4451 // If the class is abstract, we eagerly fetch the super class of the
4452 // object to avoid doing a comparison we know will fail.
4453 Label loop;
4454 __ Bind(&loop);
4455 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4456 __ MaybeUnpoisonHeapReference(out);
4457 // If `out` is null, we use it for the result, and jump to `done`.
4458 __ CompareAndBranchIfZero(out, &done);
4459 __ cmp(out, ShifterOperand(cls));
4460 __ b(&loop, NE);
4461 __ LoadImmediate(out, 1);
4462 if (zero.IsLinked()) {
4463 __ b(&done);
4464 }
4465 break;
4466 }
4467 case TypeCheckKind::kClassHierarchyCheck: {
4468 // Walk over the class hierarchy to find a match.
4469 Label loop, success;
4470 __ Bind(&loop);
4471 __ cmp(out, ShifterOperand(cls));
4472 __ b(&success, EQ);
4473 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4474 __ MaybeUnpoisonHeapReference(out);
4475 __ CompareAndBranchIfNonZero(out, &loop);
4476 // If `out` is null, we use it for the result, and jump to `done`.
4477 __ b(&done);
4478 __ Bind(&success);
4479 __ LoadImmediate(out, 1);
4480 if (zero.IsLinked()) {
4481 __ b(&done);
4482 }
4483 break;
4484 }
4485 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004486 // Do an exact check.
4487 Label exact_check;
4488 __ cmp(out, ShifterOperand(cls));
4489 __ b(&exact_check, EQ);
4490 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004491 __ LoadFromOffset(kLoadWord, out, out, component_offset);
4492 __ MaybeUnpoisonHeapReference(out);
4493 // If `out` is null, we use it for the result, and jump to `done`.
4494 __ CompareAndBranchIfZero(out, &done);
4495 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
4496 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4497 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004498 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004499 __ LoadImmediate(out, 1);
4500 __ b(&done);
4501 break;
4502 }
4503 case TypeCheckKind::kArrayCheck: {
4504 __ cmp(out, ShifterOperand(cls));
4505 DCHECK(locations->OnlyCallsOnSlowPath());
4506 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4507 instruction, /* is_fatal */ false);
4508 codegen_->AddSlowPath(slow_path);
4509 __ b(slow_path->GetEntryLabel(), NE);
4510 __ LoadImmediate(out, 1);
4511 if (zero.IsLinked()) {
4512 __ b(&done);
4513 }
4514 break;
4515 }
4516
4517 case TypeCheckKind::kInterfaceCheck:
4518 default: {
4519 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
4520 instruction,
4521 instruction->GetDexPc(),
4522 nullptr);
4523 if (zero.IsLinked()) {
4524 __ b(&done);
4525 }
4526 break;
4527 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004528 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004529
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004530 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004531 __ Bind(&zero);
4532 __ LoadImmediate(out, 0);
4533 }
4534
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004535 if (done.IsLinked()) {
4536 __ Bind(&done);
4537 }
4538
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004539 if (slow_path != nullptr) {
4540 __ Bind(slow_path->GetExitLabel());
4541 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004542}
4543
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004544void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004545 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4546 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
4547
4548 switch (instruction->GetTypeCheckKind()) {
4549 case TypeCheckKind::kExactCheck:
4550 case TypeCheckKind::kAbstractClassCheck:
4551 case TypeCheckKind::kClassHierarchyCheck:
4552 case TypeCheckKind::kArrayObjectCheck:
4553 call_kind = throws_into_catch
4554 ? LocationSummary::kCallOnSlowPath
4555 : LocationSummary::kNoCall;
4556 break;
4557 case TypeCheckKind::kInterfaceCheck:
4558 call_kind = LocationSummary::kCall;
4559 break;
4560 case TypeCheckKind::kArrayCheck:
4561 call_kind = LocationSummary::kCallOnSlowPath;
4562 break;
4563 }
4564
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004565 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004566 instruction, call_kind);
4567 if (call_kind != LocationSummary::kCall) {
4568 locations->SetInAt(0, Location::RequiresRegister());
4569 locations->SetInAt(1, Location::RequiresRegister());
4570 // Note that TypeCheckSlowPathARM uses this register too.
4571 locations->AddTemp(Location::RequiresRegister());
4572 } else {
4573 InvokeRuntimeCallingConvention calling_convention;
4574 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4575 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4576 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004577}
4578
4579void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
4580 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004581 Register obj = locations->InAt(0).AsRegister<Register>();
4582 Register cls = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004583 Register temp = locations->WillCall()
4584 ? Register(kNoRegister)
4585 : locations->GetTemp(0).AsRegister<Register>();
4586
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004587 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004588 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4589 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4590 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
4591 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004592
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004593 if (!locations->WillCall()) {
4594 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4595 instruction, !locations->CanCall());
4596 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray64acf302015-09-14 22:20:29 +01004597 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004598
4599 Label done;
4600 // Avoid null check if we know obj is not null.
4601 if (instruction->MustDoNullCheck()) {
4602 __ CompareAndBranchIfZero(obj, &done);
4603 }
4604
4605 if (locations->WillCall()) {
4606 __ LoadFromOffset(kLoadWord, obj, obj, class_offset);
4607 __ MaybeUnpoisonHeapReference(obj);
4608 } else {
4609 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
4610 __ MaybeUnpoisonHeapReference(temp);
4611 }
4612
4613 switch (instruction->GetTypeCheckKind()) {
4614 case TypeCheckKind::kExactCheck:
4615 case TypeCheckKind::kArrayCheck: {
4616 __ cmp(temp, ShifterOperand(cls));
4617 // Jump to slow path for throwing the exception or doing a
4618 // more involved array check.
4619 __ b(slow_path->GetEntryLabel(), NE);
4620 break;
4621 }
4622 case TypeCheckKind::kAbstractClassCheck: {
4623 // If the class is abstract, we eagerly fetch the super class of the
4624 // object to avoid doing a comparison we know will fail.
4625 Label loop;
4626 __ Bind(&loop);
4627 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
4628 __ MaybeUnpoisonHeapReference(temp);
4629 // Jump to the slow path to throw the exception.
4630 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
4631 __ cmp(temp, ShifterOperand(cls));
4632 __ b(&loop, NE);
4633 break;
4634 }
4635 case TypeCheckKind::kClassHierarchyCheck: {
4636 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004637 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004638 __ Bind(&loop);
4639 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004640 __ b(&done, EQ);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004641 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
4642 __ MaybeUnpoisonHeapReference(temp);
4643 __ CompareAndBranchIfNonZero(temp, &loop);
4644 // Jump to the slow path to throw the exception.
4645 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004646 break;
4647 }
4648 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004649 // Do an exact check.
4650 __ cmp(temp, ShifterOperand(cls));
4651 __ b(&done, EQ);
4652 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004653 __ LoadFromOffset(kLoadWord, temp, temp, component_offset);
4654 __ MaybeUnpoisonHeapReference(temp);
4655 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
4656 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
4657 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4658 __ CompareAndBranchIfNonZero(temp, slow_path->GetEntryLabel());
4659 break;
4660 }
4661 case TypeCheckKind::kInterfaceCheck:
4662 default:
4663 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
4664 instruction,
4665 instruction->GetDexPc(),
4666 nullptr);
4667 break;
4668 }
4669 __ Bind(&done);
4670
4671 if (slow_path != nullptr) {
4672 __ Bind(slow_path->GetExitLabel());
4673 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004674}
4675
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004676void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4677 LocationSummary* locations =
4678 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4679 InvokeRuntimeCallingConvention calling_convention;
4680 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4681}
4682
4683void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4684 codegen_->InvokeRuntime(instruction->IsEnter()
4685 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
4686 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004687 instruction->GetDexPc(),
4688 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004689}
4690
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004691void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4692void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4693void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4694
4695void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4696 LocationSummary* locations =
4697 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4698 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4699 || instruction->GetResultType() == Primitive::kPrimLong);
4700 locations->SetInAt(0, Location::RequiresRegister());
4701 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004702 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004703}
4704
4705void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
4706 HandleBitwiseOperation(instruction);
4707}
4708
4709void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
4710 HandleBitwiseOperation(instruction);
4711}
4712
4713void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
4714 HandleBitwiseOperation(instruction);
4715}
4716
4717void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4718 LocationSummary* locations = instruction->GetLocations();
4719
4720 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004721 Register first = locations->InAt(0).AsRegister<Register>();
4722 Register second = locations->InAt(1).AsRegister<Register>();
4723 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004724 if (instruction->IsAnd()) {
4725 __ and_(out, first, ShifterOperand(second));
4726 } else if (instruction->IsOr()) {
4727 __ orr(out, first, ShifterOperand(second));
4728 } else {
4729 DCHECK(instruction->IsXor());
4730 __ eor(out, first, ShifterOperand(second));
4731 }
4732 } else {
4733 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4734 Location first = locations->InAt(0);
4735 Location second = locations->InAt(1);
4736 Location out = locations->Out();
4737 if (instruction->IsAnd()) {
4738 __ and_(out.AsRegisterPairLow<Register>(),
4739 first.AsRegisterPairLow<Register>(),
4740 ShifterOperand(second.AsRegisterPairLow<Register>()));
4741 __ and_(out.AsRegisterPairHigh<Register>(),
4742 first.AsRegisterPairHigh<Register>(),
4743 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4744 } else if (instruction->IsOr()) {
4745 __ orr(out.AsRegisterPairLow<Register>(),
4746 first.AsRegisterPairLow<Register>(),
4747 ShifterOperand(second.AsRegisterPairLow<Register>()));
4748 __ orr(out.AsRegisterPairHigh<Register>(),
4749 first.AsRegisterPairHigh<Register>(),
4750 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4751 } else {
4752 DCHECK(instruction->IsXor());
4753 __ eor(out.AsRegisterPairLow<Register>(),
4754 first.AsRegisterPairLow<Register>(),
4755 ShifterOperand(second.AsRegisterPairLow<Register>()));
4756 __ eor(out.AsRegisterPairHigh<Register>(),
4757 first.AsRegisterPairHigh<Register>(),
4758 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4759 }
4760 }
4761}
4762
Nicolas Geoffray38207af2015-06-01 15:46:22 +01004763void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00004764 // For better instruction scheduling we load the direct code pointer before the method pointer.
4765 bool direct_code_loaded = false;
4766 switch (invoke->GetCodePtrLocation()) {
4767 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4768 if (IsSameDexFile(*invoke->GetTargetMethod().dex_file, GetGraph()->GetDexFile())) {
4769 break;
4770 }
4771 // Calls across dex files are more likely to exceed the available BL range,
4772 // so use absolute patch by falling through to kDirectCodeFixup.
4773 FALLTHROUGH_INTENDED;
4774 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4775 // LR = code address from literal pool with link-time patch.
4776 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
4777 direct_code_loaded = true;
4778 break;
4779 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4780 // LR = invoke->GetDirectCodePtr();
4781 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
4782 direct_code_loaded = true;
4783 break;
4784 default:
4785 break;
4786 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004787
Vladimir Marko58155012015-08-19 12:49:41 +00004788 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
4789 switch (invoke->GetMethodLoadKind()) {
4790 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
4791 // temp = thread->string_init_entrypoint
4792 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
4793 break;
4794 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
4795 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
4796 break;
4797 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
4798 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
4799 break;
4800 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
4801 __ LoadLiteral(temp.AsRegister<Register>(),
4802 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
4803 break;
4804 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
4805 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
4806 FALLTHROUGH_INTENDED;
4807 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
4808 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
4809 Register method_reg;
4810 Register reg = temp.AsRegister<Register>();
4811 if (current_method.IsRegister()) {
4812 method_reg = current_method.AsRegister<Register>();
4813 } else {
4814 DCHECK(invoke->GetLocations()->Intrinsified());
4815 DCHECK(!current_method.IsValid());
4816 method_reg = reg;
4817 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
4818 }
4819 // temp = current_method->dex_cache_resolved_methods_;
4820 __ LoadFromOffset(
Vladimir Marko05792b92015-08-03 11:56:49 +01004821 kLoadWord, reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset(
4822 kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00004823 // temp = temp[index_in_cache]
4824 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
4825 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
4826 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01004827 }
Vladimir Marko58155012015-08-19 12:49:41 +00004828 }
4829
4830 switch (invoke->GetCodePtrLocation()) {
4831 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
4832 __ bl(GetFrameEntryLabel());
4833 break;
4834 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4835 if (!direct_code_loaded) {
4836 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
4837 __ Bind(&relative_call_patches_.back().label);
4838 Label label;
4839 __ bl(&label); // Arbitrarily branch to the instruction after BL, override at link time.
4840 __ Bind(&label);
4841 break;
4842 }
4843 // If we loaded the direct code above, fall through.
4844 FALLTHROUGH_INTENDED;
4845 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4846 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4847 // LR prepared above for better instruction scheduling.
4848 DCHECK(direct_code_loaded);
4849 // LR()
4850 __ blx(LR);
4851 break;
4852 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
4853 // LR = callee_method->entry_point_from_quick_compiled_code_
4854 __ LoadFromOffset(
4855 kLoadWord, LR, callee_method.AsRegister<Register>(),
4856 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
4857 // LR()
4858 __ blx(LR);
4859 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004860 }
4861
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004862 DCHECK(!IsLeafMethod());
4863}
4864
Andreas Gampebfb5ba92015-09-01 15:45:02 +00004865void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
4866 Register temp = temp_location.AsRegister<Register>();
4867 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
4868 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
4869 LocationSummary* locations = invoke->GetLocations();
4870 Location receiver = locations->InAt(0);
4871 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4872 // temp = object->GetClass();
4873 DCHECK(receiver.IsRegister());
4874 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
4875 MaybeRecordImplicitNullCheck(invoke);
4876 __ MaybeUnpoisonHeapReference(temp);
4877 // temp = temp->GetMethodAt(method_offset);
4878 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
4879 kArmWordSize).Int32Value();
4880 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
4881 // LR = temp->GetEntryPoint();
4882 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
4883 // LR();
4884 __ blx(LR);
4885}
4886
Vladimir Marko58155012015-08-19 12:49:41 +00004887void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
4888 DCHECK(linker_patches->empty());
4889 size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
4890 linker_patches->reserve(size);
4891 for (const auto& entry : method_patches_) {
4892 const MethodReference& target_method = entry.first;
4893 Literal* literal = entry.second;
4894 DCHECK(literal->GetLabel()->IsBound());
4895 uint32_t literal_offset = literal->GetLabel()->Position();
4896 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
4897 target_method.dex_file,
4898 target_method.dex_method_index));
4899 }
4900 for (const auto& entry : call_patches_) {
4901 const MethodReference& target_method = entry.first;
4902 Literal* literal = entry.second;
4903 DCHECK(literal->GetLabel()->IsBound());
4904 uint32_t literal_offset = literal->GetLabel()->Position();
4905 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
4906 target_method.dex_file,
4907 target_method.dex_method_index));
4908 }
4909 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
4910 uint32_t literal_offset = info.label.Position();
4911 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
4912 info.target_method.dex_file,
4913 info.target_method.dex_method_index));
4914 }
4915}
4916
4917Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
4918 MethodToLiteralMap* map) {
4919 // Look up the literal for target_method.
4920 auto lb = map->lower_bound(target_method);
4921 if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
4922 return lb->second;
4923 }
4924 // We don't have a literal for this method yet, insert a new one.
4925 Literal* literal = __ NewLiteral<uint32_t>(0u);
4926 map->PutBefore(lb, target_method, literal);
4927 return literal;
4928}
4929
4930Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
4931 return DeduplicateMethodLiteral(target_method, &method_patches_);
4932}
4933
4934Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
4935 return DeduplicateMethodLiteral(target_method, &call_patches_);
4936}
4937
Calin Juravleb1498f62015-02-16 13:13:29 +00004938void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
4939 // Nothing to do, this should be removed during prepare for register allocator.
4940 UNUSED(instruction);
4941 LOG(FATAL) << "Unreachable";
4942}
4943
4944void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
4945 // Nothing to do, this should be removed during prepare for register allocator.
4946 UNUSED(instruction);
4947 LOG(FATAL) << "Unreachable";
4948}
4949
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01004950void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
4951 DCHECK(codegen_->IsBaseline());
4952 LocationSummary* locations =
4953 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4954 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
4955}
4956
4957void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
4958 DCHECK(codegen_->IsBaseline());
4959 // Will be generated at use site.
4960}
4961
Mark Mendellfe57faa2015-09-18 09:26:15 -04004962// Simple implementation of packed switch - generate cascaded compare/jumps.
4963void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
4964 LocationSummary* locations =
4965 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
4966 locations->SetInAt(0, Location::RequiresRegister());
4967}
4968
4969void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
4970 int32_t lower_bound = switch_instr->GetStartValue();
4971 int32_t num_entries = switch_instr->GetNumEntries();
4972 LocationSummary* locations = switch_instr->GetLocations();
4973 Register value_reg = locations->InAt(0).AsRegister<Register>();
4974 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
4975
4976 // Create a series of compare/jumps.
4977 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
4978 for (int32_t i = 0; i < num_entries; i++) {
4979 GenerateCompareWithImmediate(value_reg, lower_bound + i);
4980 __ b(codegen_->GetLabelOf(successors.at(i)), EQ);
4981 }
4982
4983 // And the default for any other value.
4984 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
4985 __ b(codegen_->GetLabelOf(default_block));
4986 }
4987}
4988
Andreas Gampe85b62f22015-09-09 13:15:38 -07004989void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
4990 if (!trg.IsValid()) {
4991 DCHECK(type == Primitive::kPrimVoid);
4992 return;
4993 }
4994
4995 DCHECK_NE(type, Primitive::kPrimVoid);
4996
4997 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
4998 if (return_loc.Equals(trg)) {
4999 return;
5000 }
5001
5002 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
5003 // with the last branch.
5004 if (type == Primitive::kPrimLong) {
5005 HParallelMove parallel_move(GetGraph()->GetArena());
5006 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
5007 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
5008 GetMoveResolver()->EmitNativeCode(&parallel_move);
5009 } else if (type == Primitive::kPrimDouble) {
5010 HParallelMove parallel_move(GetGraph()->GetArena());
5011 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
5012 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
5013 GetMoveResolver()->EmitNativeCode(&parallel_move);
5014 } else {
5015 // Let the parallel move resolver take care of all of this.
5016 HParallelMove parallel_move(GetGraph()->GetArena());
5017 parallel_move.AddMove(return_loc, trg, type, nullptr);
5018 GetMoveResolver()->EmitNativeCode(&parallel_move);
5019 }
5020}
5021
Roland Levillain4d027112015-07-01 15:41:14 +01005022#undef __
5023#undef QUICK_ENTRY_POINT
5024
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00005025} // namespace arm
5026} // namespace art