blob: f29e2ba8afda0e7d5684c984ec474f458705bccd [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)),
431 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
432 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100433 compiler_options,
434 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100435 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100436 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100437 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100438 move_resolver_(graph->GetArena(), this),
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000439 assembler_(),
Vladimir Marko58155012015-08-19 12:49:41 +0000440 isa_features_(isa_features),
Vladimir Marko5233f932015-09-29 19:01:15 +0100441 method_patches_(MethodReferenceComparator(),
442 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
443 call_patches_(MethodReferenceComparator(),
444 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
445 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700446 // Always save the LR register to mimic Quick.
447 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100448}
449
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000450void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
451 // Ensure that we fix up branches and literal loads and emit the literal pool.
452 __ FinalizeCode();
453
454 // Adjust native pc offsets in stack maps.
455 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
456 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
457 uint32_t new_position = __ GetAdjustedPosition(old_position);
458 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
459 }
460 // Adjust native pc offsets of block labels.
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100461 for (HBasicBlock* block : *block_order_) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000462 // Get the label directly from block_labels_ rather than through GetLabelOf() to avoid
463 // FirstNonEmptyBlock() which could lead to adjusting a label more than once.
Vladimir Marko225b6462015-09-28 12:17:40 +0100464 DCHECK_LT(block->GetBlockId(), GetGraph()->GetBlocks().size());
465 Label* block_label = &block_labels_[block->GetBlockId()];
David Brazdilfc6a86a2015-06-26 10:33:45 +0000466 DCHECK_EQ(block_label->IsBound(), !block->IsSingleJump());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000467 if (block_label->IsBound()) {
468 __ AdjustLabelPosition(block_label);
469 }
470 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100471 // Adjust pc offsets for the disassembly information.
472 if (disasm_info_ != nullptr) {
473 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
474 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
475 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
476 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
477 it.second.start = __ GetAdjustedPosition(it.second.start);
478 it.second.end = __ GetAdjustedPosition(it.second.end);
479 }
480 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
481 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
482 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
483 }
484 }
Vladimir Marko58155012015-08-19 12:49:41 +0000485 // Adjust pc offsets for relative call patches.
486 for (MethodPatchInfo<Label>& info : relative_call_patches_) {
487 __ AdjustLabelPosition(&info.label);
488 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000489
490 CodeGenerator::Finalize(allocator);
491}
492
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100493Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100494 switch (type) {
495 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100496 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100497 ArmManagedRegister pair =
498 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100499 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
500 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
501
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100502 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
503 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100504 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100505 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100506 }
507
508 case Primitive::kPrimByte:
509 case Primitive::kPrimBoolean:
510 case Primitive::kPrimChar:
511 case Primitive::kPrimShort:
512 case Primitive::kPrimInt:
513 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100514 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100515 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100516 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
517 ArmManagedRegister current =
518 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
519 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100520 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100521 }
522 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100523 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100524 }
525
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000526 case Primitive::kPrimFloat: {
527 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100528 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100529 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100530
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000531 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000532 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
533 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000534 return Location::FpuRegisterPairLocation(reg, reg + 1);
535 }
536
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100537 case Primitive::kPrimVoid:
538 LOG(FATAL) << "Unreachable type " << type;
539 }
540
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100541 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100542}
543
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000544void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100545 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100546 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100547
548 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100549 blocked_core_registers_[SP] = true;
550 blocked_core_registers_[LR] = true;
551 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100552
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100553 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100554 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100555
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100556 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100557 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100558
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000559 if (is_baseline) {
560 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
561 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
562 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000563
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000564 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
565
566 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
567 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
568 }
569 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100570
571 UpdateBlockedPairRegisters();
572}
573
574void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
575 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
576 ArmManagedRegister current =
577 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
578 if (blocked_core_registers_[current.AsRegisterPairLow()]
579 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
580 blocked_register_pairs_[i] = true;
581 }
582 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100583}
584
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100585InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
586 : HGraphVisitor(graph),
587 assembler_(codegen->GetAssembler()),
588 codegen_(codegen) {}
589
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000590void CodeGeneratorARM::ComputeSpillMask() {
591 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000592 // Save one extra register for baseline. Note that on thumb2, there is no easy
593 // instruction to restore just the PC, so this actually helps both baseline
594 // and non-baseline to save and restore at least two registers at entry and exit.
595 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000596 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
597 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
598 // We use vpush and vpop for saving and restoring floating point registers, which take
599 // a SRegister and the number of registers to save/restore after that SRegister. We
600 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
601 // but in the range.
602 if (fpu_spill_mask_ != 0) {
603 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
604 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
605 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
606 fpu_spill_mask_ |= (1 << i);
607 }
608 }
609}
610
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100611static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100612 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100613}
614
615static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100616 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100617}
618
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000619void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000620 bool skip_overflow_check =
621 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000622 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000623 __ Bind(&frame_entry_label_);
624
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000625 if (HasEmptyFrame()) {
626 return;
627 }
628
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100629 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000630 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
631 __ LoadFromOffset(kLoadWord, IP, IP, 0);
632 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100633 }
634
Andreas Gampe501fd632015-09-10 16:11:06 -0700635 __ PushList(core_spill_mask_);
636 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
637 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000638 if (fpu_spill_mask_ != 0) {
639 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
640 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100641 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100642 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000643 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100644 int adjust = GetFrameSize() - FrameEntrySpillSize();
645 __ AddConstant(SP, -adjust);
646 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100647 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000648}
649
650void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000651 if (HasEmptyFrame()) {
652 __ bx(LR);
653 return;
654 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100655 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100656 int adjust = GetFrameSize() - FrameEntrySpillSize();
657 __ AddConstant(SP, adjust);
658 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000659 if (fpu_spill_mask_ != 0) {
660 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
661 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100662 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
663 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000664 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700665 // Pop LR into PC to return.
666 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
667 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
668 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100669 __ cfi().RestoreState();
670 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000671}
672
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100673void CodeGeneratorARM::Bind(HBasicBlock* block) {
674 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000675}
676
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100677Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
678 switch (load->GetType()) {
679 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100680 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100681 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100682
683 case Primitive::kPrimInt:
684 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100685 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100686 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100687
688 case Primitive::kPrimBoolean:
689 case Primitive::kPrimByte:
690 case Primitive::kPrimChar:
691 case Primitive::kPrimShort:
692 case Primitive::kPrimVoid:
693 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700694 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100695 }
696
697 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700698 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100699}
700
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100701Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100702 switch (type) {
703 case Primitive::kPrimBoolean:
704 case Primitive::kPrimByte:
705 case Primitive::kPrimChar:
706 case Primitive::kPrimShort:
707 case Primitive::kPrimInt:
708 case Primitive::kPrimNot: {
709 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000710 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100711 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100712 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100713 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000714 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100715 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100716 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100717
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000718 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100719 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000720 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100721 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000722 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100723 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000724 if (calling_convention.GetRegisterAt(index) == R1) {
725 // Skip R1, and use R2_R3 instead.
726 gp_index_++;
727 index++;
728 }
729 }
730 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
731 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000732 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +0100733
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000734 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000735 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100736 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000737 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
738 }
739 }
740
741 case Primitive::kPrimFloat: {
742 uint32_t stack_index = stack_index_++;
743 if (float_index_ % 2 == 0) {
744 float_index_ = std::max(double_index_, float_index_);
745 }
746 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
747 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
748 } else {
749 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
750 }
751 }
752
753 case Primitive::kPrimDouble: {
754 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
755 uint32_t stack_index = stack_index_;
756 stack_index_ += 2;
757 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
758 uint32_t index = double_index_;
759 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000760 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000761 calling_convention.GetFpuRegisterAt(index),
762 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000763 DCHECK(ExpectedPairLayout(result));
764 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000765 } else {
766 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100767 }
768 }
769
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100770 case Primitive::kPrimVoid:
771 LOG(FATAL) << "Unexpected parameter type " << type;
772 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100773 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100774 return Location();
775}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100776
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100777Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000778 switch (type) {
779 case Primitive::kPrimBoolean:
780 case Primitive::kPrimByte:
781 case Primitive::kPrimChar:
782 case Primitive::kPrimShort:
783 case Primitive::kPrimInt:
784 case Primitive::kPrimNot: {
785 return Location::RegisterLocation(R0);
786 }
787
788 case Primitive::kPrimFloat: {
789 return Location::FpuRegisterLocation(S0);
790 }
791
792 case Primitive::kPrimLong: {
793 return Location::RegisterPairLocation(R0, R1);
794 }
795
796 case Primitive::kPrimDouble: {
797 return Location::FpuRegisterPairLocation(S0, S1);
798 }
799
800 case Primitive::kPrimVoid:
801 return Location();
802 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100803
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000804 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000805}
806
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100807Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
808 return Location::RegisterLocation(kMethodRegisterArgument);
809}
810
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100811void CodeGeneratorARM::Move32(Location destination, Location source) {
812 if (source.Equals(destination)) {
813 return;
814 }
815 if (destination.IsRegister()) {
816 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000817 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100818 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000819 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100820 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000821 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100822 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100823 } else if (destination.IsFpuRegister()) {
824 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000825 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100826 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000827 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100828 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000829 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100830 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100831 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000832 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100833 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000834 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100835 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000836 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100837 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000838 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100839 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
840 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100841 }
842 }
843}
844
845void CodeGeneratorARM::Move64(Location destination, Location source) {
846 if (source.Equals(destination)) {
847 return;
848 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100849 if (destination.IsRegisterPair()) {
850 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000851 EmitParallelMoves(
852 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
853 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100854 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000855 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100856 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
857 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100858 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000859 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100860 } else {
861 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000862 DCHECK(ExpectedPairLayout(destination));
863 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
864 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100865 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000866 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100867 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000868 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
869 SP,
870 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100871 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000872 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100873 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100874 } else {
875 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100876 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000877 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100878 if (source.AsRegisterPairLow<Register>() == R1) {
879 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100880 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
881 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100882 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100883 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100884 SP, destination.GetStackIndex());
885 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000886 } else if (source.IsFpuRegisterPair()) {
887 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
888 SP,
889 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100890 } else {
891 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000892 EmitParallelMoves(
893 Location::StackSlot(source.GetStackIndex()),
894 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100895 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000896 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100897 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
898 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100899 }
900 }
901}
902
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100903void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100904 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100905 if (instruction->IsCurrentMethod()) {
906 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
907 } else if (locations != nullptr && locations->Out().Equals(location)) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100908 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100909 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000910 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000911 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
912 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +0000913 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000914 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000915 } else {
916 DCHECK(location.IsStackSlot());
917 __ LoadImmediate(IP, value);
918 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
919 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000920 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000921 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000922 int64_t value = const_to_move->AsLongConstant()->GetValue();
923 if (location.IsRegisterPair()) {
924 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
925 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
926 } else {
927 DCHECK(location.IsDoubleStackSlot());
928 __ LoadImmediate(IP, Low32Bits(value));
929 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
930 __ LoadImmediate(IP, High32Bits(value));
931 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
932 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100933 }
Roland Levillain476df552014-10-09 17:51:36 +0100934 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100935 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
936 switch (instruction->GetType()) {
937 case Primitive::kPrimBoolean:
938 case Primitive::kPrimByte:
939 case Primitive::kPrimChar:
940 case Primitive::kPrimShort:
941 case Primitive::kPrimInt:
942 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100943 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100944 Move32(location, Location::StackSlot(stack_slot));
945 break;
946
947 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100948 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100949 Move64(location, Location::DoubleStackSlot(stack_slot));
950 break;
951
952 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100953 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100954 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000955 } else if (instruction->IsTemporary()) {
956 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000957 if (temp_location.IsStackSlot()) {
958 Move32(location, temp_location);
959 } else {
960 DCHECK(temp_location.IsDoubleStackSlot());
961 Move64(location, temp_location);
962 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000963 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100964 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100965 switch (instruction->GetType()) {
966 case Primitive::kPrimBoolean:
967 case Primitive::kPrimByte:
968 case Primitive::kPrimChar:
969 case Primitive::kPrimShort:
970 case Primitive::kPrimNot:
971 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100972 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100973 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100974 break;
975
976 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100977 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100978 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100979 break;
980
981 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100982 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100983 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000984 }
985}
986
Calin Juravle175dc732015-08-25 15:42:32 +0100987void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
988 DCHECK(location.IsRegister());
989 __ LoadImmediate(location.AsRegister<Register>(), value);
990}
991
992void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
993 HInstruction* instruction,
994 uint32_t dex_pc,
995 SlowPathCode* slow_path) {
996 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
997 instruction,
998 dex_pc,
999 slow_path);
1000}
1001
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001002void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1003 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001004 uint32_t dex_pc,
1005 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001006 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001007 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1008 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001009 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001010}
1011
David Brazdilfc6a86a2015-06-26 10:33:45 +00001012void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001013 DCHECK(!successor->IsExitBlock());
1014
1015 HBasicBlock* block = got->GetBlock();
1016 HInstruction* previous = got->GetPrevious();
1017
1018 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001019 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001020 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1021 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1022 return;
1023 }
1024
1025 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1026 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1027 }
1028 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001029 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001030 }
1031}
1032
David Brazdilfc6a86a2015-06-26 10:33:45 +00001033void LocationsBuilderARM::VisitGoto(HGoto* got) {
1034 got->SetLocations(nullptr);
1035}
1036
1037void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1038 HandleGoto(got, got->GetSuccessor());
1039}
1040
1041void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1042 try_boundary->SetLocations(nullptr);
1043}
1044
1045void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1046 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1047 if (!successor->IsExitBlock()) {
1048 HandleGoto(try_boundary, successor);
1049 }
1050}
1051
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001052void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001053 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001054}
1055
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001056void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001057 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001058}
1059
Roland Levillain4fa13f62015-07-06 18:11:54 +01001060void InstructionCodeGeneratorARM::GenerateCompareWithImmediate(Register left, int32_t right) {
1061 ShifterOperand operand;
1062 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, right, &operand)) {
1063 __ cmp(left, operand);
1064 } else {
1065 Register temp = IP;
1066 __ LoadImmediate(temp, right);
1067 __ cmp(left, ShifterOperand(temp));
1068 }
1069}
1070
1071void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1072 Label* true_label,
1073 Label* false_label) {
1074 __ vmstat(); // transfer FP status register to ARM APSR.
1075 if (cond->IsFPConditionTrueIfNaN()) {
1076 __ b(true_label, VS); // VS for unordered.
1077 } else if (cond->IsFPConditionFalseIfNaN()) {
1078 __ b(false_label, VS); // VS for unordered.
1079 }
1080 __ b(true_label, ARMSignedOrFPCondition(cond->GetCondition()));
1081}
1082
1083void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1084 Label* true_label,
1085 Label* false_label) {
1086 LocationSummary* locations = cond->GetLocations();
1087 Location left = locations->InAt(0);
1088 Location right = locations->InAt(1);
1089 IfCondition if_cond = cond->GetCondition();
1090
1091 Register left_high = left.AsRegisterPairHigh<Register>();
1092 Register left_low = left.AsRegisterPairLow<Register>();
1093 IfCondition true_high_cond = if_cond;
1094 IfCondition false_high_cond = cond->GetOppositeCondition();
1095 Condition final_condition = ARMUnsignedCondition(if_cond);
1096
1097 // Set the conditions for the test, remembering that == needs to be
1098 // decided using the low words.
1099 switch (if_cond) {
1100 case kCondEQ:
1101 case kCondNE:
1102 // Nothing to do.
1103 break;
1104 case kCondLT:
1105 false_high_cond = kCondGT;
1106 break;
1107 case kCondLE:
1108 true_high_cond = kCondLT;
1109 break;
1110 case kCondGT:
1111 false_high_cond = kCondLT;
1112 break;
1113 case kCondGE:
1114 true_high_cond = kCondGT;
1115 break;
1116 }
1117 if (right.IsConstant()) {
1118 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1119 int32_t val_low = Low32Bits(value);
1120 int32_t val_high = High32Bits(value);
1121
1122 GenerateCompareWithImmediate(left_high, val_high);
1123 if (if_cond == kCondNE) {
1124 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1125 } else if (if_cond == kCondEQ) {
1126 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1127 } else {
1128 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1129 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1130 }
1131 // Must be equal high, so compare the lows.
1132 GenerateCompareWithImmediate(left_low, val_low);
1133 } else {
1134 Register right_high = right.AsRegisterPairHigh<Register>();
1135 Register right_low = right.AsRegisterPairLow<Register>();
1136
1137 __ cmp(left_high, ShifterOperand(right_high));
1138 if (if_cond == kCondNE) {
1139 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1140 } else if (if_cond == kCondEQ) {
1141 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1142 } else {
1143 __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
1144 __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
1145 }
1146 // Must be equal high, so compare the lows.
1147 __ cmp(left_low, ShifterOperand(right_low));
1148 }
1149 // The last comparison might be unsigned.
1150 __ b(true_label, final_condition);
1151}
1152
1153void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HIf* if_instr,
1154 HCondition* condition,
1155 Label* true_target,
1156 Label* false_target,
1157 Label* always_true_target) {
1158 LocationSummary* locations = condition->GetLocations();
1159 Location left = locations->InAt(0);
1160 Location right = locations->InAt(1);
1161
1162 // We don't want true_target as a nullptr.
1163 if (true_target == nullptr) {
1164 true_target = always_true_target;
1165 }
1166 bool falls_through = (false_target == nullptr);
1167
1168 // FP compares don't like null false_targets.
1169 if (false_target == nullptr) {
1170 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1171 }
1172
1173 Primitive::Type type = condition->InputAt(0)->GetType();
1174 switch (type) {
1175 case Primitive::kPrimLong:
1176 GenerateLongComparesAndJumps(condition, true_target, false_target);
1177 break;
1178 case Primitive::kPrimFloat:
1179 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1180 GenerateFPJumps(condition, true_target, false_target);
1181 break;
1182 case Primitive::kPrimDouble:
1183 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1184 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1185 GenerateFPJumps(condition, true_target, false_target);
1186 break;
1187 default:
1188 LOG(FATAL) << "Unexpected compare type " << type;
1189 }
1190
1191 if (!falls_through) {
1192 __ b(false_target);
1193 }
1194}
1195
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001196void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
1197 Label* true_target,
1198 Label* false_target,
1199 Label* always_true_target) {
1200 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001201 if (cond->IsIntConstant()) {
1202 // Constant condition, statically compared against 1.
1203 int32_t cond_value = cond->AsIntConstant()->GetValue();
1204 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001205 if (always_true_target != nullptr) {
1206 __ b(always_true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001207 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001208 return;
1209 } else {
1210 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001211 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001212 } else {
1213 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1214 // Condition has been materialized, compare the output to 0
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001215 DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01001216 __ CompareAndBranchIfNonZero(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
1217 true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001218 } else {
1219 // Condition has not been materialized, use its inputs as the
1220 // comparison and its condition as the branch condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001221 Primitive::Type type =
1222 cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
1223 // Is this a long or FP comparison that has been folded into the HCondition?
1224 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1225 // Generate the comparison directly.
1226 GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
1227 true_target, false_target, always_true_target);
1228 return;
1229 }
1230
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001231 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001232 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001233 Register left = locations->InAt(0).AsRegister<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001234 Location right = locations->InAt(1);
1235 if (right.IsRegister()) {
1236 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001237 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001238 DCHECK(right.IsConstant());
1239 GenerateCompareWithImmediate(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001240 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001241 __ b(true_target, ARMSignedOrFPCondition(cond->AsCondition()->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001242 }
Dave Allison20dfc792014-06-16 20:44:29 -07001243 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001244 if (false_target != nullptr) {
1245 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001246 }
1247}
1248
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001249void LocationsBuilderARM::VisitIf(HIf* if_instr) {
1250 LocationSummary* locations =
1251 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1252 HInstruction* cond = if_instr->InputAt(0);
1253 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1254 locations->SetInAt(0, Location::RequiresRegister());
1255 }
1256}
1257
1258void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
1259 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1260 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1261 Label* always_true_target = true_target;
1262 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1263 if_instr->IfTrueSuccessor())) {
1264 always_true_target = nullptr;
1265 }
1266 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1267 if_instr->IfFalseSuccessor())) {
1268 false_target = nullptr;
1269 }
1270 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1271}
1272
1273void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1274 LocationSummary* locations = new (GetGraph()->GetArena())
1275 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1276 HInstruction* cond = deoptimize->InputAt(0);
1277 DCHECK(cond->IsCondition());
1278 if (cond->AsCondition()->NeedsMaterialization()) {
1279 locations->SetInAt(0, Location::RequiresRegister());
1280 }
1281}
1282
1283void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001284 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001285 DeoptimizationSlowPathARM(deoptimize);
1286 codegen_->AddSlowPath(slow_path);
1287 Label* slow_path_entry = slow_path->GetEntryLabel();
1288 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1289}
Dave Allison20dfc792014-06-16 20:44:29 -07001290
Roland Levillain0d37cd02015-05-27 16:39:19 +01001291void LocationsBuilderARM::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001292 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001293 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001294 // Handle the long/FP comparisons made in instruction simplification.
1295 switch (cond->InputAt(0)->GetType()) {
1296 case Primitive::kPrimLong:
1297 locations->SetInAt(0, Location::RequiresRegister());
1298 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1299 if (cond->NeedsMaterialization()) {
1300 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1301 }
1302 break;
1303
1304 case Primitive::kPrimFloat:
1305 case Primitive::kPrimDouble:
1306 locations->SetInAt(0, Location::RequiresFpuRegister());
1307 locations->SetInAt(1, Location::RequiresFpuRegister());
1308 if (cond->NeedsMaterialization()) {
1309 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1310 }
1311 break;
1312
1313 default:
1314 locations->SetInAt(0, Location::RequiresRegister());
1315 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1316 if (cond->NeedsMaterialization()) {
1317 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1318 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001319 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001320}
1321
Roland Levillain0d37cd02015-05-27 16:39:19 +01001322void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001323 if (!cond->NeedsMaterialization()) {
1324 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001325 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001326
1327 LocationSummary* locations = cond->GetLocations();
1328 Location left = locations->InAt(0);
1329 Location right = locations->InAt(1);
1330 Register out = locations->Out().AsRegister<Register>();
1331 Label true_label, false_label;
1332
1333 switch (cond->InputAt(0)->GetType()) {
1334 default: {
1335 // Integer case.
1336 if (right.IsRegister()) {
1337 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1338 } else {
1339 DCHECK(right.IsConstant());
1340 GenerateCompareWithImmediate(left.AsRegister<Register>(),
1341 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1342 }
1343 __ it(ARMSignedOrFPCondition(cond->GetCondition()), kItElse);
1344 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
1345 ARMSignedOrFPCondition(cond->GetCondition()));
1346 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
1347 ARMSignedOrFPCondition(cond->GetOppositeCondition()));
1348 return;
1349 }
1350 case Primitive::kPrimLong:
1351 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1352 break;
1353 case Primitive::kPrimFloat:
1354 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1355 GenerateFPJumps(cond, &true_label, &false_label);
1356 break;
1357 case Primitive::kPrimDouble:
1358 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1359 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1360 GenerateFPJumps(cond, &true_label, &false_label);
1361 break;
1362 }
1363
1364 // Convert the jumps into the result.
1365 Label done_label;
1366
1367 // False case: result = 0.
1368 __ Bind(&false_label);
1369 __ LoadImmediate(out, 0);
1370 __ b(&done_label);
1371
1372 // True case: result = 1.
1373 __ Bind(&true_label);
1374 __ LoadImmediate(out, 1);
1375 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001376}
1377
1378void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1379 VisitCondition(comp);
1380}
1381
1382void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1383 VisitCondition(comp);
1384}
1385
1386void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1387 VisitCondition(comp);
1388}
1389
1390void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1391 VisitCondition(comp);
1392}
1393
1394void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1395 VisitCondition(comp);
1396}
1397
1398void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1399 VisitCondition(comp);
1400}
1401
1402void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1403 VisitCondition(comp);
1404}
1405
1406void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1407 VisitCondition(comp);
1408}
1409
1410void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1411 VisitCondition(comp);
1412}
1413
1414void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1415 VisitCondition(comp);
1416}
1417
1418void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1419 VisitCondition(comp);
1420}
1421
1422void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1423 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001424}
1425
1426void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001427 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001428}
1429
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001430void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1431 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001432}
1433
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001434void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001435 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001436}
1437
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001438void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001439 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001440 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001441}
1442
1443void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001444 LocationSummary* locations =
1445 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001446 switch (store->InputAt(1)->GetType()) {
1447 case Primitive::kPrimBoolean:
1448 case Primitive::kPrimByte:
1449 case Primitive::kPrimChar:
1450 case Primitive::kPrimShort:
1451 case Primitive::kPrimInt:
1452 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001453 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001454 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1455 break;
1456
1457 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001458 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001459 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1460 break;
1461
1462 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001463 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001464 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001465}
1466
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001467void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001468 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001469}
1470
1471void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001472 LocationSummary* locations =
1473 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001474 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001475}
1476
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001477void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001478 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001479 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001480}
1481
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001482void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1483 LocationSummary* locations =
1484 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1485 locations->SetOut(Location::ConstantLocation(constant));
1486}
1487
1488void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
1489 // Will be generated at use site.
1490 UNUSED(constant);
1491}
1492
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001493void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001494 LocationSummary* locations =
1495 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001496 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001497}
1498
1499void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1500 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001501 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001502}
1503
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001504void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1505 LocationSummary* locations =
1506 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1507 locations->SetOut(Location::ConstantLocation(constant));
1508}
1509
1510void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1511 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001512 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001513}
1514
1515void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1516 LocationSummary* locations =
1517 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1518 locations->SetOut(Location::ConstantLocation(constant));
1519}
1520
1521void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1522 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001523 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001524}
1525
Calin Juravle27df7582015-04-17 19:12:31 +01001526void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1527 memory_barrier->SetLocations(nullptr);
1528}
1529
1530void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1531 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1532}
1533
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001534void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001535 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001536}
1537
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001538void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001539 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001540 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001541}
1542
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001543void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001544 LocationSummary* locations =
1545 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001546 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001547}
1548
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001549void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001550 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001551 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001552}
1553
Calin Juravle175dc732015-08-25 15:42:32 +01001554void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1555 // The trampoline uses the same calling convention as dex calling conventions,
1556 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1557 // the method_idx.
1558 HandleInvoke(invoke);
1559}
1560
1561void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1562 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1563}
1564
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001565void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001566 // When we do not run baseline, explicit clinit checks triggered by static
1567 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1568 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001569
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001570 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1571 codegen_->GetInstructionSetFeatures());
1572 if (intrinsic.TryDispatch(invoke)) {
1573 return;
1574 }
1575
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001576 HandleInvoke(invoke);
1577}
1578
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001579static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1580 if (invoke->GetLocations()->Intrinsified()) {
1581 IntrinsicCodeGeneratorARM intrinsic(codegen);
1582 intrinsic.Dispatch(invoke);
1583 return true;
1584 }
1585 return false;
1586}
1587
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001588void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001589 // When we do not run baseline, explicit clinit checks triggered by static
1590 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1591 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001592
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001593 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1594 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001595 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001596
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001597 LocationSummary* locations = invoke->GetLocations();
1598 codegen_->GenerateStaticOrDirectCall(
1599 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001600 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001601}
1602
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001603void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001604 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001605 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001606}
1607
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001608void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001609 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1610 codegen_->GetInstructionSetFeatures());
1611 if (intrinsic.TryDispatch(invoke)) {
1612 return;
1613 }
1614
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001615 HandleInvoke(invoke);
1616}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001617
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001618void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001619 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1620 return;
1621 }
1622
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001623 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001624 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001625 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001626}
1627
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001628void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1629 HandleInvoke(invoke);
1630 // Add the hidden argument.
1631 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1632}
1633
1634void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1635 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001636 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001637 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1638 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001639 LocationSummary* locations = invoke->GetLocations();
1640 Location receiver = locations->InAt(0);
1641 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1642
1643 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001644 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1645 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001646
1647 // temp = object->GetClass();
1648 if (receiver.IsStackSlot()) {
1649 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1650 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1651 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001652 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001653 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001654 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001655 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001656 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001657 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001658 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001659 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1660 // LR = temp->GetEntryPoint();
1661 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1662 // LR();
1663 __ blx(LR);
1664 DCHECK(!codegen_->IsLeafMethod());
1665 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1666}
1667
Roland Levillain88cb1752014-10-20 16:36:47 +01001668void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1669 LocationSummary* locations =
1670 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1671 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001672 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001673 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001674 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1675 break;
1676 }
1677 case Primitive::kPrimLong: {
1678 locations->SetInAt(0, Location::RequiresRegister());
1679 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001680 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001681 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001682
Roland Levillain88cb1752014-10-20 16:36:47 +01001683 case Primitive::kPrimFloat:
1684 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001685 locations->SetInAt(0, Location::RequiresFpuRegister());
1686 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001687 break;
1688
1689 default:
1690 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1691 }
1692}
1693
1694void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1695 LocationSummary* locations = neg->GetLocations();
1696 Location out = locations->Out();
1697 Location in = locations->InAt(0);
1698 switch (neg->GetResultType()) {
1699 case Primitive::kPrimInt:
1700 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001701 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001702 break;
1703
1704 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001705 DCHECK(in.IsRegisterPair());
1706 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1707 __ rsbs(out.AsRegisterPairLow<Register>(),
1708 in.AsRegisterPairLow<Register>(),
1709 ShifterOperand(0));
1710 // We cannot emit an RSC (Reverse Subtract with Carry)
1711 // instruction here, as it does not exist in the Thumb-2
1712 // instruction set. We use the following approach
1713 // using SBC and SUB instead.
1714 //
1715 // out.hi = -C
1716 __ sbc(out.AsRegisterPairHigh<Register>(),
1717 out.AsRegisterPairHigh<Register>(),
1718 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1719 // out.hi = out.hi - in.hi
1720 __ sub(out.AsRegisterPairHigh<Register>(),
1721 out.AsRegisterPairHigh<Register>(),
1722 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1723 break;
1724
Roland Levillain88cb1752014-10-20 16:36:47 +01001725 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001726 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001727 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001728 break;
1729
Roland Levillain88cb1752014-10-20 16:36:47 +01001730 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001731 DCHECK(in.IsFpuRegisterPair());
1732 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1733 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001734 break;
1735
1736 default:
1737 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1738 }
1739}
1740
Roland Levillaindff1f282014-11-05 14:15:05 +00001741void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001742 Primitive::Type result_type = conversion->GetResultType();
1743 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001744 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001745
Roland Levillain5b3ee562015-04-14 16:02:41 +01001746 // The float-to-long, double-to-long and long-to-float type conversions
1747 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001748 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01001749 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1750 && result_type == Primitive::kPrimLong)
1751 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00001752 ? LocationSummary::kCall
1753 : LocationSummary::kNoCall;
1754 LocationSummary* locations =
1755 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1756
David Brazdilb2bd1c52015-03-25 11:17:37 +00001757 // The Java language does not allow treating boolean as an integral type but
1758 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001759
Roland Levillaindff1f282014-11-05 14:15:05 +00001760 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001761 case Primitive::kPrimByte:
1762 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001763 case Primitive::kPrimBoolean:
1764 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001765 case Primitive::kPrimShort:
1766 case Primitive::kPrimInt:
1767 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001768 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001769 locations->SetInAt(0, Location::RequiresRegister());
1770 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1771 break;
1772
1773 default:
1774 LOG(FATAL) << "Unexpected type conversion from " << input_type
1775 << " to " << result_type;
1776 }
1777 break;
1778
Roland Levillain01a8d712014-11-14 16:27:39 +00001779 case Primitive::kPrimShort:
1780 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001781 case Primitive::kPrimBoolean:
1782 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001783 case Primitive::kPrimByte:
1784 case Primitive::kPrimInt:
1785 case Primitive::kPrimChar:
1786 // Processing a Dex `int-to-short' instruction.
1787 locations->SetInAt(0, Location::RequiresRegister());
1788 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1789 break;
1790
1791 default:
1792 LOG(FATAL) << "Unexpected type conversion from " << input_type
1793 << " to " << result_type;
1794 }
1795 break;
1796
Roland Levillain946e1432014-11-11 17:35:19 +00001797 case Primitive::kPrimInt:
1798 switch (input_type) {
1799 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001800 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001801 locations->SetInAt(0, Location::Any());
1802 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1803 break;
1804
1805 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001806 // Processing a Dex `float-to-int' instruction.
1807 locations->SetInAt(0, Location::RequiresFpuRegister());
1808 locations->SetOut(Location::RequiresRegister());
1809 locations->AddTemp(Location::RequiresFpuRegister());
1810 break;
1811
Roland Levillain946e1432014-11-11 17:35:19 +00001812 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001813 // Processing a Dex `double-to-int' instruction.
1814 locations->SetInAt(0, Location::RequiresFpuRegister());
1815 locations->SetOut(Location::RequiresRegister());
1816 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001817 break;
1818
1819 default:
1820 LOG(FATAL) << "Unexpected type conversion from " << input_type
1821 << " to " << result_type;
1822 }
1823 break;
1824
Roland Levillaindff1f282014-11-05 14:15:05 +00001825 case Primitive::kPrimLong:
1826 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001827 case Primitive::kPrimBoolean:
1828 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001829 case Primitive::kPrimByte:
1830 case Primitive::kPrimShort:
1831 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001832 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001833 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001834 locations->SetInAt(0, Location::RequiresRegister());
1835 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1836 break;
1837
Roland Levillain624279f2014-12-04 11:54:28 +00001838 case Primitive::kPrimFloat: {
1839 // Processing a Dex `float-to-long' instruction.
1840 InvokeRuntimeCallingConvention calling_convention;
1841 locations->SetInAt(0, Location::FpuRegisterLocation(
1842 calling_convention.GetFpuRegisterAt(0)));
1843 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1844 break;
1845 }
1846
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001847 case Primitive::kPrimDouble: {
1848 // Processing a Dex `double-to-long' instruction.
1849 InvokeRuntimeCallingConvention calling_convention;
1850 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1851 calling_convention.GetFpuRegisterAt(0),
1852 calling_convention.GetFpuRegisterAt(1)));
1853 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001854 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001855 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001856
1857 default:
1858 LOG(FATAL) << "Unexpected type conversion from " << input_type
1859 << " to " << result_type;
1860 }
1861 break;
1862
Roland Levillain981e4542014-11-14 11:47:14 +00001863 case Primitive::kPrimChar:
1864 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001865 case Primitive::kPrimBoolean:
1866 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001867 case Primitive::kPrimByte:
1868 case Primitive::kPrimShort:
1869 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001870 // Processing a Dex `int-to-char' instruction.
1871 locations->SetInAt(0, Location::RequiresRegister());
1872 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1873 break;
1874
1875 default:
1876 LOG(FATAL) << "Unexpected type conversion from " << input_type
1877 << " to " << result_type;
1878 }
1879 break;
1880
Roland Levillaindff1f282014-11-05 14:15:05 +00001881 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001882 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001883 case Primitive::kPrimBoolean:
1884 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001885 case Primitive::kPrimByte:
1886 case Primitive::kPrimShort:
1887 case Primitive::kPrimInt:
1888 case Primitive::kPrimChar:
1889 // Processing a Dex `int-to-float' instruction.
1890 locations->SetInAt(0, Location::RequiresRegister());
1891 locations->SetOut(Location::RequiresFpuRegister());
1892 break;
1893
Roland Levillain5b3ee562015-04-14 16:02:41 +01001894 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00001895 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01001896 InvokeRuntimeCallingConvention calling_convention;
1897 locations->SetInAt(0, Location::RegisterPairLocation(
1898 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
1899 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00001900 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01001901 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00001902
Roland Levillaincff13742014-11-17 14:32:17 +00001903 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001904 // Processing a Dex `double-to-float' instruction.
1905 locations->SetInAt(0, Location::RequiresFpuRegister());
1906 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001907 break;
1908
1909 default:
1910 LOG(FATAL) << "Unexpected type conversion from " << input_type
1911 << " to " << result_type;
1912 };
1913 break;
1914
Roland Levillaindff1f282014-11-05 14:15:05 +00001915 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001916 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001917 case Primitive::kPrimBoolean:
1918 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001919 case Primitive::kPrimByte:
1920 case Primitive::kPrimShort:
1921 case Primitive::kPrimInt:
1922 case Primitive::kPrimChar:
1923 // Processing a Dex `int-to-double' instruction.
1924 locations->SetInAt(0, Location::RequiresRegister());
1925 locations->SetOut(Location::RequiresFpuRegister());
1926 break;
1927
1928 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001929 // Processing a Dex `long-to-double' instruction.
1930 locations->SetInAt(0, Location::RequiresRegister());
1931 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01001932 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001933 locations->AddTemp(Location::RequiresFpuRegister());
1934 break;
1935
Roland Levillaincff13742014-11-17 14:32:17 +00001936 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001937 // Processing a Dex `float-to-double' instruction.
1938 locations->SetInAt(0, Location::RequiresFpuRegister());
1939 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001940 break;
1941
1942 default:
1943 LOG(FATAL) << "Unexpected type conversion from " << input_type
1944 << " to " << result_type;
1945 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001946 break;
1947
1948 default:
1949 LOG(FATAL) << "Unexpected type conversion from " << input_type
1950 << " to " << result_type;
1951 }
1952}
1953
1954void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1955 LocationSummary* locations = conversion->GetLocations();
1956 Location out = locations->Out();
1957 Location in = locations->InAt(0);
1958 Primitive::Type result_type = conversion->GetResultType();
1959 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001960 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001961 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001962 case Primitive::kPrimByte:
1963 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001964 case Primitive::kPrimBoolean:
1965 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001966 case Primitive::kPrimShort:
1967 case Primitive::kPrimInt:
1968 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001969 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001970 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001971 break;
1972
1973 default:
1974 LOG(FATAL) << "Unexpected type conversion from " << input_type
1975 << " to " << result_type;
1976 }
1977 break;
1978
Roland Levillain01a8d712014-11-14 16:27:39 +00001979 case Primitive::kPrimShort:
1980 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001981 case Primitive::kPrimBoolean:
1982 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001983 case Primitive::kPrimByte:
1984 case Primitive::kPrimInt:
1985 case Primitive::kPrimChar:
1986 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001987 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00001988 break;
1989
1990 default:
1991 LOG(FATAL) << "Unexpected type conversion from " << input_type
1992 << " to " << result_type;
1993 }
1994 break;
1995
Roland Levillain946e1432014-11-11 17:35:19 +00001996 case Primitive::kPrimInt:
1997 switch (input_type) {
1998 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001999 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002000 DCHECK(out.IsRegister());
2001 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002002 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002003 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002004 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002005 } else {
2006 DCHECK(in.IsConstant());
2007 DCHECK(in.GetConstant()->IsLongConstant());
2008 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002009 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002010 }
2011 break;
2012
Roland Levillain3f8f9362014-12-02 17:45:01 +00002013 case Primitive::kPrimFloat: {
2014 // Processing a Dex `float-to-int' instruction.
2015 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2016 __ vmovs(temp, in.AsFpuRegister<SRegister>());
2017 __ vcvtis(temp, temp);
2018 __ vmovrs(out.AsRegister<Register>(), temp);
2019 break;
2020 }
2021
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002022 case Primitive::kPrimDouble: {
2023 // Processing a Dex `double-to-int' instruction.
2024 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2025 DRegister temp_d = FromLowSToD(temp_s);
2026 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2027 __ vcvtid(temp_s, temp_d);
2028 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002029 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002030 }
Roland Levillain946e1432014-11-11 17:35:19 +00002031
2032 default:
2033 LOG(FATAL) << "Unexpected type conversion from " << input_type
2034 << " to " << result_type;
2035 }
2036 break;
2037
Roland Levillaindff1f282014-11-05 14:15:05 +00002038 case Primitive::kPrimLong:
2039 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002040 case Primitive::kPrimBoolean:
2041 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002042 case Primitive::kPrimByte:
2043 case Primitive::kPrimShort:
2044 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002045 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002046 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002047 DCHECK(out.IsRegisterPair());
2048 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002049 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002050 // Sign extension.
2051 __ Asr(out.AsRegisterPairHigh<Register>(),
2052 out.AsRegisterPairLow<Register>(),
2053 31);
2054 break;
2055
2056 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002057 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002058 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2059 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002060 conversion->GetDexPc(),
2061 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002062 break;
2063
Roland Levillaindff1f282014-11-05 14:15:05 +00002064 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002065 // Processing a Dex `double-to-long' instruction.
2066 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2067 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002068 conversion->GetDexPc(),
2069 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002070 break;
2071
2072 default:
2073 LOG(FATAL) << "Unexpected type conversion from " << input_type
2074 << " to " << result_type;
2075 }
2076 break;
2077
Roland Levillain981e4542014-11-14 11:47:14 +00002078 case Primitive::kPrimChar:
2079 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002080 case Primitive::kPrimBoolean:
2081 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002082 case Primitive::kPrimByte:
2083 case Primitive::kPrimShort:
2084 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002085 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002086 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002087 break;
2088
2089 default:
2090 LOG(FATAL) << "Unexpected type conversion from " << input_type
2091 << " to " << result_type;
2092 }
2093 break;
2094
Roland Levillaindff1f282014-11-05 14:15:05 +00002095 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002096 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002097 case Primitive::kPrimBoolean:
2098 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002099 case Primitive::kPrimByte:
2100 case Primitive::kPrimShort:
2101 case Primitive::kPrimInt:
2102 case Primitive::kPrimChar: {
2103 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002104 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2105 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002106 break;
2107 }
2108
Roland Levillain5b3ee562015-04-14 16:02:41 +01002109 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002110 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002111 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2112 conversion,
2113 conversion->GetDexPc(),
2114 nullptr);
Roland Levillain6d0e4832014-11-27 18:31:21 +00002115 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002116
Roland Levillaincff13742014-11-17 14:32:17 +00002117 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002118 // Processing a Dex `double-to-float' instruction.
2119 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2120 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002121 break;
2122
2123 default:
2124 LOG(FATAL) << "Unexpected type conversion from " << input_type
2125 << " to " << result_type;
2126 };
2127 break;
2128
Roland Levillaindff1f282014-11-05 14:15:05 +00002129 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002130 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002131 case Primitive::kPrimBoolean:
2132 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002133 case Primitive::kPrimByte:
2134 case Primitive::kPrimShort:
2135 case Primitive::kPrimInt:
2136 case Primitive::kPrimChar: {
2137 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002138 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002139 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2140 out.AsFpuRegisterPairLow<SRegister>());
2141 break;
2142 }
2143
Roland Levillain647b9ed2014-11-27 12:06:00 +00002144 case Primitive::kPrimLong: {
2145 // Processing a Dex `long-to-double' instruction.
2146 Register low = in.AsRegisterPairLow<Register>();
2147 Register high = in.AsRegisterPairHigh<Register>();
2148 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2149 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002150 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002151 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002152 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2153 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002154
Roland Levillain682393c2015-04-14 15:57:52 +01002155 // temp_d = int-to-double(high)
2156 __ vmovsr(temp_s, high);
2157 __ vcvtdi(temp_d, temp_s);
2158 // constant_d = k2Pow32EncodingForDouble
2159 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2160 // out_d = unsigned-to-double(low)
2161 __ vmovsr(out_s, low);
2162 __ vcvtdu(out_d, out_s);
2163 // out_d += temp_d * constant_d
2164 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002165 break;
2166 }
2167
Roland Levillaincff13742014-11-17 14:32:17 +00002168 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002169 // Processing a Dex `float-to-double' instruction.
2170 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2171 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002172 break;
2173
2174 default:
2175 LOG(FATAL) << "Unexpected type conversion from " << input_type
2176 << " to " << result_type;
2177 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002178 break;
2179
2180 default:
2181 LOG(FATAL) << "Unexpected type conversion from " << input_type
2182 << " to " << result_type;
2183 }
2184}
2185
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002186void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002187 LocationSummary* locations =
2188 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002189 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002190 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002191 locations->SetInAt(0, Location::RequiresRegister());
2192 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002193 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2194 break;
2195 }
2196
2197 case Primitive::kPrimLong: {
2198 locations->SetInAt(0, Location::RequiresRegister());
2199 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002200 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002201 break;
2202 }
2203
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002204 case Primitive::kPrimFloat:
2205 case Primitive::kPrimDouble: {
2206 locations->SetInAt(0, Location::RequiresFpuRegister());
2207 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002208 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002209 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002210 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002211
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002212 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002213 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002214 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002215}
2216
2217void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2218 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002219 Location out = locations->Out();
2220 Location first = locations->InAt(0);
2221 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002222 switch (add->GetResultType()) {
2223 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002224 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002225 __ add(out.AsRegister<Register>(),
2226 first.AsRegister<Register>(),
2227 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002228 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002229 __ AddConstant(out.AsRegister<Register>(),
2230 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002231 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002232 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002233 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002234
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002235 case Primitive::kPrimLong: {
2236 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002237 __ adds(out.AsRegisterPairLow<Register>(),
2238 first.AsRegisterPairLow<Register>(),
2239 ShifterOperand(second.AsRegisterPairLow<Register>()));
2240 __ adc(out.AsRegisterPairHigh<Register>(),
2241 first.AsRegisterPairHigh<Register>(),
2242 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002243 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002244 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002245
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002246 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002247 __ vadds(out.AsFpuRegister<SRegister>(),
2248 first.AsFpuRegister<SRegister>(),
2249 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002250 break;
2251
2252 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002253 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2254 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2255 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002256 break;
2257
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002258 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002259 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002260 }
2261}
2262
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002263void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002264 LocationSummary* locations =
2265 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002266 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002267 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002268 locations->SetInAt(0, Location::RequiresRegister());
2269 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002270 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2271 break;
2272 }
2273
2274 case Primitive::kPrimLong: {
2275 locations->SetInAt(0, Location::RequiresRegister());
2276 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002277 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002278 break;
2279 }
Calin Juravle11351682014-10-23 15:38:15 +01002280 case Primitive::kPrimFloat:
2281 case Primitive::kPrimDouble: {
2282 locations->SetInAt(0, Location::RequiresFpuRegister());
2283 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002284 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002285 break;
Calin Juravle11351682014-10-23 15:38:15 +01002286 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002287 default:
Calin Juravle11351682014-10-23 15:38:15 +01002288 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002289 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002290}
2291
2292void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2293 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002294 Location out = locations->Out();
2295 Location first = locations->InAt(0);
2296 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002297 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002298 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002299 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002300 __ sub(out.AsRegister<Register>(),
2301 first.AsRegister<Register>(),
2302 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002303 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002304 __ AddConstant(out.AsRegister<Register>(),
2305 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002306 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002307 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002308 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002309 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002310
Calin Juravle11351682014-10-23 15:38:15 +01002311 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002312 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002313 __ subs(out.AsRegisterPairLow<Register>(),
2314 first.AsRegisterPairLow<Register>(),
2315 ShifterOperand(second.AsRegisterPairLow<Register>()));
2316 __ sbc(out.AsRegisterPairHigh<Register>(),
2317 first.AsRegisterPairHigh<Register>(),
2318 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002319 break;
Calin Juravle11351682014-10-23 15:38:15 +01002320 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002321
Calin Juravle11351682014-10-23 15:38:15 +01002322 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002323 __ vsubs(out.AsFpuRegister<SRegister>(),
2324 first.AsFpuRegister<SRegister>(),
2325 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002326 break;
Calin Juravle11351682014-10-23 15:38:15 +01002327 }
2328
2329 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002330 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2331 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2332 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002333 break;
2334 }
2335
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002336
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002337 default:
Calin Juravle11351682014-10-23 15:38:15 +01002338 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002339 }
2340}
2341
Calin Juravle34bacdf2014-10-07 20:23:36 +01002342void LocationsBuilderARM::VisitMul(HMul* mul) {
2343 LocationSummary* locations =
2344 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2345 switch (mul->GetResultType()) {
2346 case Primitive::kPrimInt:
2347 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002348 locations->SetInAt(0, Location::RequiresRegister());
2349 locations->SetInAt(1, Location::RequiresRegister());
2350 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002351 break;
2352 }
2353
Calin Juravleb5bfa962014-10-21 18:02:24 +01002354 case Primitive::kPrimFloat:
2355 case Primitive::kPrimDouble: {
2356 locations->SetInAt(0, Location::RequiresFpuRegister());
2357 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002358 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002359 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002360 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002361
2362 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002363 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002364 }
2365}
2366
2367void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2368 LocationSummary* locations = mul->GetLocations();
2369 Location out = locations->Out();
2370 Location first = locations->InAt(0);
2371 Location second = locations->InAt(1);
2372 switch (mul->GetResultType()) {
2373 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002374 __ mul(out.AsRegister<Register>(),
2375 first.AsRegister<Register>(),
2376 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002377 break;
2378 }
2379 case Primitive::kPrimLong: {
2380 Register out_hi = out.AsRegisterPairHigh<Register>();
2381 Register out_lo = out.AsRegisterPairLow<Register>();
2382 Register in1_hi = first.AsRegisterPairHigh<Register>();
2383 Register in1_lo = first.AsRegisterPairLow<Register>();
2384 Register in2_hi = second.AsRegisterPairHigh<Register>();
2385 Register in2_lo = second.AsRegisterPairLow<Register>();
2386
2387 // Extra checks to protect caused by the existence of R1_R2.
2388 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2389 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2390 DCHECK_NE(out_hi, in1_lo);
2391 DCHECK_NE(out_hi, in2_lo);
2392
2393 // input: in1 - 64 bits, in2 - 64 bits
2394 // output: out
2395 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2396 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2397 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2398
2399 // IP <- in1.lo * in2.hi
2400 __ mul(IP, in1_lo, in2_hi);
2401 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2402 __ mla(out_hi, in1_hi, in2_lo, IP);
2403 // out.lo <- (in1.lo * in2.lo)[31:0];
2404 __ umull(out_lo, IP, in1_lo, in2_lo);
2405 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2406 __ add(out_hi, out_hi, ShifterOperand(IP));
2407 break;
2408 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002409
2410 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002411 __ vmuls(out.AsFpuRegister<SRegister>(),
2412 first.AsFpuRegister<SRegister>(),
2413 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002414 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002415 }
2416
2417 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002418 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2419 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2420 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002421 break;
2422 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002423
2424 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002425 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002426 }
2427}
2428
Zheng Xuc6667102015-05-15 16:08:45 +08002429void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2430 DCHECK(instruction->IsDiv() || instruction->IsRem());
2431 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2432
2433 LocationSummary* locations = instruction->GetLocations();
2434 Location second = locations->InAt(1);
2435 DCHECK(second.IsConstant());
2436
2437 Register out = locations->Out().AsRegister<Register>();
2438 Register dividend = locations->InAt(0).AsRegister<Register>();
2439 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2440 DCHECK(imm == 1 || imm == -1);
2441
2442 if (instruction->IsRem()) {
2443 __ LoadImmediate(out, 0);
2444 } else {
2445 if (imm == 1) {
2446 __ Mov(out, dividend);
2447 } else {
2448 __ rsb(out, dividend, ShifterOperand(0));
2449 }
2450 }
2451}
2452
2453void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2454 DCHECK(instruction->IsDiv() || instruction->IsRem());
2455 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2456
2457 LocationSummary* locations = instruction->GetLocations();
2458 Location second = locations->InAt(1);
2459 DCHECK(second.IsConstant());
2460
2461 Register out = locations->Out().AsRegister<Register>();
2462 Register dividend = locations->InAt(0).AsRegister<Register>();
2463 Register temp = locations->GetTemp(0).AsRegister<Register>();
2464 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Vladimir Marko80afd022015-05-19 18:08:00 +01002465 uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002466 DCHECK(IsPowerOfTwo(abs_imm));
2467 int ctz_imm = CTZ(abs_imm);
2468
2469 if (ctz_imm == 1) {
2470 __ Lsr(temp, dividend, 32 - ctz_imm);
2471 } else {
2472 __ Asr(temp, dividend, 31);
2473 __ Lsr(temp, temp, 32 - ctz_imm);
2474 }
2475 __ add(out, temp, ShifterOperand(dividend));
2476
2477 if (instruction->IsDiv()) {
2478 __ Asr(out, out, ctz_imm);
2479 if (imm < 0) {
2480 __ rsb(out, out, ShifterOperand(0));
2481 }
2482 } else {
2483 __ ubfx(out, out, 0, ctz_imm);
2484 __ sub(out, out, ShifterOperand(temp));
2485 }
2486}
2487
2488void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2489 DCHECK(instruction->IsDiv() || instruction->IsRem());
2490 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2491
2492 LocationSummary* locations = instruction->GetLocations();
2493 Location second = locations->InAt(1);
2494 DCHECK(second.IsConstant());
2495
2496 Register out = locations->Out().AsRegister<Register>();
2497 Register dividend = locations->InAt(0).AsRegister<Register>();
2498 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2499 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2500 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2501
2502 int64_t magic;
2503 int shift;
2504 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2505
2506 __ LoadImmediate(temp1, magic);
2507 __ smull(temp2, temp1, dividend, temp1);
2508
2509 if (imm > 0 && magic < 0) {
2510 __ add(temp1, temp1, ShifterOperand(dividend));
2511 } else if (imm < 0 && magic > 0) {
2512 __ sub(temp1, temp1, ShifterOperand(dividend));
2513 }
2514
2515 if (shift != 0) {
2516 __ Asr(temp1, temp1, shift);
2517 }
2518
2519 if (instruction->IsDiv()) {
2520 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2521 } else {
2522 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2523 // TODO: Strength reduction for mls.
2524 __ LoadImmediate(temp2, imm);
2525 __ mls(out, temp1, temp2, dividend);
2526 }
2527}
2528
2529void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2530 DCHECK(instruction->IsDiv() || instruction->IsRem());
2531 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2532
2533 LocationSummary* locations = instruction->GetLocations();
2534 Location second = locations->InAt(1);
2535 DCHECK(second.IsConstant());
2536
2537 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2538 if (imm == 0) {
2539 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2540 } else if (imm == 1 || imm == -1) {
2541 DivRemOneOrMinusOne(instruction);
2542 } else if (IsPowerOfTwo(std::abs(imm))) {
2543 DivRemByPowerOfTwo(instruction);
2544 } else {
2545 DCHECK(imm <= -2 || imm >= 2);
2546 GenerateDivRemWithAnyConstant(instruction);
2547 }
2548}
2549
Calin Juravle7c4954d2014-10-28 16:57:40 +00002550void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002551 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2552 if (div->GetResultType() == Primitive::kPrimLong) {
2553 // pLdiv runtime call.
2554 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002555 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2556 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002557 } else if (div->GetResultType() == Primitive::kPrimInt &&
2558 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2559 // pIdivmod runtime call.
2560 call_kind = LocationSummary::kCall;
2561 }
2562
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002563 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2564
Calin Juravle7c4954d2014-10-28 16:57:40 +00002565 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002566 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002567 if (div->InputAt(1)->IsConstant()) {
2568 locations->SetInAt(0, Location::RequiresRegister());
2569 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
2570 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2571 int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2572 if (abs_imm <= 1) {
2573 // No temp register required.
2574 } else {
2575 locations->AddTemp(Location::RequiresRegister());
2576 if (!IsPowerOfTwo(abs_imm)) {
2577 locations->AddTemp(Location::RequiresRegister());
2578 }
2579 }
2580 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002581 locations->SetInAt(0, Location::RequiresRegister());
2582 locations->SetInAt(1, Location::RequiresRegister());
2583 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2584 } else {
2585 InvokeRuntimeCallingConvention calling_convention;
2586 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2587 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2588 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2589 // we only need the former.
2590 locations->SetOut(Location::RegisterLocation(R0));
2591 }
Calin Juravled0d48522014-11-04 16:40:20 +00002592 break;
2593 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002594 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002595 InvokeRuntimeCallingConvention calling_convention;
2596 locations->SetInAt(0, Location::RegisterPairLocation(
2597 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2598 locations->SetInAt(1, Location::RegisterPairLocation(
2599 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002600 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002601 break;
2602 }
2603 case Primitive::kPrimFloat:
2604 case Primitive::kPrimDouble: {
2605 locations->SetInAt(0, Location::RequiresFpuRegister());
2606 locations->SetInAt(1, Location::RequiresFpuRegister());
2607 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2608 break;
2609 }
2610
2611 default:
2612 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2613 }
2614}
2615
2616void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2617 LocationSummary* locations = div->GetLocations();
2618 Location out = locations->Out();
2619 Location first = locations->InAt(0);
2620 Location second = locations->InAt(1);
2621
2622 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002623 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002624 if (second.IsConstant()) {
2625 GenerateDivRemConstantIntegral(div);
2626 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002627 __ sdiv(out.AsRegister<Register>(),
2628 first.AsRegister<Register>(),
2629 second.AsRegister<Register>());
2630 } else {
2631 InvokeRuntimeCallingConvention calling_convention;
2632 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2633 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2634 DCHECK_EQ(R0, out.AsRegister<Register>());
2635
2636 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2637 }
Calin Juravled0d48522014-11-04 16:40:20 +00002638 break;
2639 }
2640
Calin Juravle7c4954d2014-10-28 16:57:40 +00002641 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002642 InvokeRuntimeCallingConvention calling_convention;
2643 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2644 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2645 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2646 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2647 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002648 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002649
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002650 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002651 break;
2652 }
2653
2654 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002655 __ vdivs(out.AsFpuRegister<SRegister>(),
2656 first.AsFpuRegister<SRegister>(),
2657 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002658 break;
2659 }
2660
2661 case Primitive::kPrimDouble: {
2662 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2663 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2664 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2665 break;
2666 }
2667
2668 default:
2669 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2670 }
2671}
2672
Calin Juravlebacfec32014-11-14 15:54:36 +00002673void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002674 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002675
2676 // Most remainders are implemented in the runtime.
2677 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002678 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
2679 // sdiv will be replaced by other instruction sequence.
2680 call_kind = LocationSummary::kNoCall;
2681 } else if ((rem->GetResultType() == Primitive::kPrimInt)
2682 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002683 // Have hardware divide instruction for int, do it with three instructions.
2684 call_kind = LocationSummary::kNoCall;
2685 }
2686
Calin Juravlebacfec32014-11-14 15:54:36 +00002687 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2688
Calin Juravled2ec87d2014-12-08 14:24:46 +00002689 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002690 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002691 if (rem->InputAt(1)->IsConstant()) {
2692 locations->SetInAt(0, Location::RequiresRegister());
2693 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
2694 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2695 int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
2696 if (abs_imm <= 1) {
2697 // No temp register required.
2698 } else {
2699 locations->AddTemp(Location::RequiresRegister());
2700 if (!IsPowerOfTwo(abs_imm)) {
2701 locations->AddTemp(Location::RequiresRegister());
2702 }
2703 }
2704 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002705 locations->SetInAt(0, Location::RequiresRegister());
2706 locations->SetInAt(1, Location::RequiresRegister());
2707 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2708 locations->AddTemp(Location::RequiresRegister());
2709 } else {
2710 InvokeRuntimeCallingConvention calling_convention;
2711 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2712 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2713 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2714 // we only need the latter.
2715 locations->SetOut(Location::RegisterLocation(R1));
2716 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002717 break;
2718 }
2719 case Primitive::kPrimLong: {
2720 InvokeRuntimeCallingConvention calling_convention;
2721 locations->SetInAt(0, Location::RegisterPairLocation(
2722 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2723 locations->SetInAt(1, Location::RegisterPairLocation(
2724 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2725 // The runtime helper puts the output in R2,R3.
2726 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2727 break;
2728 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002729 case Primitive::kPrimFloat: {
2730 InvokeRuntimeCallingConvention calling_convention;
2731 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2732 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2733 locations->SetOut(Location::FpuRegisterLocation(S0));
2734 break;
2735 }
2736
Calin Juravlebacfec32014-11-14 15:54:36 +00002737 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002738 InvokeRuntimeCallingConvention calling_convention;
2739 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2740 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2741 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2742 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2743 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002744 break;
2745 }
2746
2747 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002748 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002749 }
2750}
2751
2752void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2753 LocationSummary* locations = rem->GetLocations();
2754 Location out = locations->Out();
2755 Location first = locations->InAt(0);
2756 Location second = locations->InAt(1);
2757
Calin Juravled2ec87d2014-12-08 14:24:46 +00002758 Primitive::Type type = rem->GetResultType();
2759 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002760 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002761 if (second.IsConstant()) {
2762 GenerateDivRemConstantIntegral(rem);
2763 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002764 Register reg1 = first.AsRegister<Register>();
2765 Register reg2 = second.AsRegister<Register>();
2766 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002767
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002768 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002769 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002770 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002771 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002772 } else {
2773 InvokeRuntimeCallingConvention calling_convention;
2774 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2775 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2776 DCHECK_EQ(R1, out.AsRegister<Register>());
2777
2778 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2779 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002780 break;
2781 }
2782
2783 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002784 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002785 break;
2786 }
2787
Calin Juravled2ec87d2014-12-08 14:24:46 +00002788 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002789 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002790 break;
2791 }
2792
Calin Juravlebacfec32014-11-14 15:54:36 +00002793 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002794 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002795 break;
2796 }
2797
2798 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002799 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002800 }
2801}
2802
Calin Juravled0d48522014-11-04 16:40:20 +00002803void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00002804 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
2805 ? LocationSummary::kCallOnSlowPath
2806 : LocationSummary::kNoCall;
2807 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002808 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002809 if (instruction->HasUses()) {
2810 locations->SetOut(Location::SameAsFirstInput());
2811 }
2812}
2813
2814void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07002815 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00002816 codegen_->AddSlowPath(slow_path);
2817
2818 LocationSummary* locations = instruction->GetLocations();
2819 Location value = locations->InAt(0);
2820
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002821 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06002822 case Primitive::kPrimByte:
2823 case Primitive::kPrimChar:
2824 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002825 case Primitive::kPrimInt: {
2826 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01002827 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002828 } else {
2829 DCHECK(value.IsConstant()) << value;
2830 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2831 __ b(slow_path->GetEntryLabel());
2832 }
2833 }
2834 break;
2835 }
2836 case Primitive::kPrimLong: {
2837 if (value.IsRegisterPair()) {
2838 __ orrs(IP,
2839 value.AsRegisterPairLow<Register>(),
2840 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2841 __ b(slow_path->GetEntryLabel(), EQ);
2842 } else {
2843 DCHECK(value.IsConstant()) << value;
2844 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2845 __ b(slow_path->GetEntryLabel());
2846 }
2847 }
2848 break;
2849 default:
2850 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2851 }
2852 }
Calin Juravled0d48522014-11-04 16:40:20 +00002853}
2854
Calin Juravle9aec02f2014-11-18 23:06:35 +00002855void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2856 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2857
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002858 LocationSummary* locations =
2859 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002860
2861 switch (op->GetResultType()) {
2862 case Primitive::kPrimInt: {
2863 locations->SetInAt(0, Location::RequiresRegister());
2864 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002865 // Make the output overlap, as it will be used to hold the masked
2866 // second input.
2867 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002868 break;
2869 }
2870 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002871 locations->SetInAt(0, Location::RequiresRegister());
2872 locations->SetInAt(1, Location::RequiresRegister());
2873 locations->AddTemp(Location::RequiresRegister());
2874 locations->SetOut(Location::RequiresRegister());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002875 break;
2876 }
2877 default:
2878 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2879 }
2880}
2881
2882void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2883 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2884
2885 LocationSummary* locations = op->GetLocations();
2886 Location out = locations->Out();
2887 Location first = locations->InAt(0);
2888 Location second = locations->InAt(1);
2889
2890 Primitive::Type type = op->GetResultType();
2891 switch (type) {
2892 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002893 Register out_reg = out.AsRegister<Register>();
2894 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002895 // Arm doesn't mask the shift count so we need to do it ourselves.
2896 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002897 Register second_reg = second.AsRegister<Register>();
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002898 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
Calin Juravle9aec02f2014-11-18 23:06:35 +00002899 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002900 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002901 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002902 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002903 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002904 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002905 }
2906 } else {
2907 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2908 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2909 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2910 __ Mov(out_reg, first_reg);
2911 } else if (op->IsShl()) {
2912 __ Lsl(out_reg, first_reg, shift_value);
2913 } else if (op->IsShr()) {
2914 __ Asr(out_reg, first_reg, shift_value);
2915 } else {
2916 __ Lsr(out_reg, first_reg, shift_value);
2917 }
2918 }
2919 break;
2920 }
2921 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002922 Register o_h = out.AsRegisterPairHigh<Register>();
2923 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002924
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002925 Register temp = locations->GetTemp(0).AsRegister<Register>();
2926
2927 Register high = first.AsRegisterPairHigh<Register>();
2928 Register low = first.AsRegisterPairLow<Register>();
2929
2930 Register second_reg = second.AsRegister<Register>();
2931
Calin Juravle9aec02f2014-11-18 23:06:35 +00002932 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002933 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002934 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002935 __ Lsl(o_h, high, o_l);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002936 // Shift the low part and `or` what overflew on the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002937 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002938 __ Lsr(temp, low, temp);
2939 __ orr(o_h, o_h, ShifterOperand(temp));
2940 // If the shift is > 32 bits, override the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002941 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002942 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002943 __ Lsl(o_h, low, temp, PL);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002944 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002945 __ Lsl(o_l, low, o_l);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002946 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002947 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002948 // Shift the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002949 __ Lsr(o_l, low, o_h);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002950 // Shift the high part and `or` what underflew on the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002951 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002952 __ Lsl(temp, high, temp);
2953 __ orr(o_l, o_l, ShifterOperand(temp));
2954 // If the shift is > 32 bits, override the low part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002955 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002956 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002957 __ Asr(o_l, high, temp, PL);
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002958 // Shift the high part
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002959 __ Asr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002960 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002961 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002962 // same as Shr except we use `Lsr`s and not `Asr`s
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002963 __ Lsr(o_l, low, o_h);
2964 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002965 __ Lsl(temp, high, temp);
2966 __ orr(o_l, o_l, ShifterOperand(temp));
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002967 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002968 __ it(PL);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002969 __ Lsr(o_l, high, temp, PL);
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01002970 __ Lsr(o_h, high, o_h);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002971 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00002972 break;
2973 }
2974 default:
2975 LOG(FATAL) << "Unexpected operation type " << type;
2976 }
2977}
2978
2979void LocationsBuilderARM::VisitShl(HShl* shl) {
2980 HandleShift(shl);
2981}
2982
2983void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
2984 HandleShift(shl);
2985}
2986
2987void LocationsBuilderARM::VisitShr(HShr* shr) {
2988 HandleShift(shr);
2989}
2990
2991void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
2992 HandleShift(shr);
2993}
2994
2995void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
2996 HandleShift(ushr);
2997}
2998
2999void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3000 HandleShift(ushr);
3001}
3002
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003003void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003004 LocationSummary* locations =
3005 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003006 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003007 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003008 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003009 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003010}
3011
3012void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
3013 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003014 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003015 // Note: if heap poisoning is enabled, the entry point takes cares
3016 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003017 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003018 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003019 instruction->GetDexPc(),
3020 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003021}
3022
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003023void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3024 LocationSummary* locations =
3025 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3026 InvokeRuntimeCallingConvention calling_convention;
3027 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003028 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003029 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003030 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003031}
3032
3033void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3034 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003035 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003036 // Note: if heap poisoning is enabled, the entry point takes cares
3037 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003038 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003039 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003040 instruction->GetDexPc(),
3041 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003042}
3043
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003044void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003045 LocationSummary* locations =
3046 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003047 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3048 if (location.IsStackSlot()) {
3049 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3050 } else if (location.IsDoubleStackSlot()) {
3051 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003052 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003053 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003054}
3055
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003056void InstructionCodeGeneratorARM::VisitParameterValue(
3057 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003058 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003059}
3060
3061void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3062 LocationSummary* locations =
3063 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3064 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3065}
3066
3067void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3068 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003069}
3070
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003071void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003072 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003073 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003074 locations->SetInAt(0, Location::RequiresRegister());
3075 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003076}
3077
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003078void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3079 LocationSummary* locations = not_->GetLocations();
3080 Location out = locations->Out();
3081 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003082 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003083 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003084 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003085 break;
3086
3087 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003088 __ mvn(out.AsRegisterPairLow<Register>(),
3089 ShifterOperand(in.AsRegisterPairLow<Register>()));
3090 __ mvn(out.AsRegisterPairHigh<Register>(),
3091 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003092 break;
3093
3094 default:
3095 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3096 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003097}
3098
David Brazdil66d126e2015-04-03 16:02:44 +01003099void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3100 LocationSummary* locations =
3101 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3102 locations->SetInAt(0, Location::RequiresRegister());
3103 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3104}
3105
3106void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003107 LocationSummary* locations = bool_not->GetLocations();
3108 Location out = locations->Out();
3109 Location in = locations->InAt(0);
3110 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3111}
3112
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003113void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003114 LocationSummary* locations =
3115 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003116 switch (compare->InputAt(0)->GetType()) {
3117 case Primitive::kPrimLong: {
3118 locations->SetInAt(0, Location::RequiresRegister());
3119 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003120 // Output overlaps because it is written before doing the low comparison.
3121 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003122 break;
3123 }
3124 case Primitive::kPrimFloat:
3125 case Primitive::kPrimDouble: {
3126 locations->SetInAt(0, Location::RequiresFpuRegister());
3127 locations->SetInAt(1, Location::RequiresFpuRegister());
3128 locations->SetOut(Location::RequiresRegister());
3129 break;
3130 }
3131 default:
3132 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3133 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003134}
3135
3136void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003137 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003138 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003139 Location left = locations->InAt(0);
3140 Location right = locations->InAt(1);
3141
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003142 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003143 Primitive::Type type = compare->InputAt(0)->GetType();
3144 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003145 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003146 __ cmp(left.AsRegisterPairHigh<Register>(),
3147 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003148 __ b(&less, LT);
3149 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003150 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003151 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003152 __ cmp(left.AsRegisterPairLow<Register>(),
3153 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00003154 break;
3155 }
3156 case Primitive::kPrimFloat:
3157 case Primitive::kPrimDouble: {
3158 __ LoadImmediate(out, 0);
3159 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003160 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003161 } else {
3162 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3163 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3164 }
3165 __ vmstat(); // transfer FP status register to ARM APSR.
3166 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003167 break;
3168 }
3169 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003170 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003171 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003172 __ b(&done, EQ);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003173 __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats.
Calin Juravleddb7df22014-11-25 20:56:51 +00003174
3175 __ Bind(&greater);
3176 __ LoadImmediate(out, 1);
3177 __ b(&done);
3178
3179 __ Bind(&less);
3180 __ LoadImmediate(out, -1);
3181
3182 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003183}
3184
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003185void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003186 LocationSummary* locations =
3187 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003188 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3189 locations->SetInAt(i, Location::Any());
3190 }
3191 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003192}
3193
3194void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003195 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003196 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003197}
3198
Calin Juravle52c48962014-12-16 17:02:57 +00003199void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3200 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07003201 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00003202 switch (kind) {
3203 case MemBarrierKind::kAnyStore:
3204 case MemBarrierKind::kLoadAny:
3205 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003206 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003207 break;
3208 }
3209 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003210 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003211 break;
3212 }
3213 default:
3214 LOG(FATAL) << "Unexpected memory barrier " << kind;
3215 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003216 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003217}
3218
3219void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3220 uint32_t offset,
3221 Register out_lo,
3222 Register out_hi) {
3223 if (offset != 0) {
3224 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003225 __ add(IP, addr, ShifterOperand(out_lo));
3226 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003227 }
3228 __ ldrexd(out_lo, out_hi, addr);
3229}
3230
3231void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3232 uint32_t offset,
3233 Register value_lo,
3234 Register value_hi,
3235 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003236 Register temp2,
3237 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003238 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003239 if (offset != 0) {
3240 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003241 __ add(IP, addr, ShifterOperand(temp1));
3242 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003243 }
3244 __ Bind(&fail);
3245 // We need a load followed by store. (The address used in a STREX instruction must
3246 // be the same as the address in the most recently executed LDREX instruction.)
3247 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003248 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003249 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003250 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003251}
3252
3253void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3254 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3255
Nicolas Geoffray39468442014-09-02 15:17:15 +01003256 LocationSummary* locations =
3257 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003258 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003259
Calin Juravle52c48962014-12-16 17:02:57 +00003260 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003261 if (Primitive::IsFloatingPointType(field_type)) {
3262 locations->SetInAt(1, Location::RequiresFpuRegister());
3263 } else {
3264 locations->SetInAt(1, Location::RequiresRegister());
3265 }
3266
Calin Juravle52c48962014-12-16 17:02:57 +00003267 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003268 bool generate_volatile = field_info.IsVolatile()
3269 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003270 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003271 bool needs_write_barrier =
3272 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003273 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003274 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003275 if (needs_write_barrier) {
3276 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003277 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003278 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00003279 // Arm encoding have some additional constraints for ldrexd/strexd:
3280 // - registers need to be consecutive
3281 // - the first register should be even but not R14.
3282 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3283 // enable Arm encoding.
3284 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3285
3286 locations->AddTemp(Location::RequiresRegister());
3287 locations->AddTemp(Location::RequiresRegister());
3288 if (field_type == Primitive::kPrimDouble) {
3289 // For doubles we need two more registers to copy the value.
3290 locations->AddTemp(Location::RegisterLocation(R2));
3291 locations->AddTemp(Location::RegisterLocation(R3));
3292 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003293 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003294}
3295
Calin Juravle52c48962014-12-16 17:02:57 +00003296void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003297 const FieldInfo& field_info,
3298 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003299 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3300
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003301 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003302 Register base = locations->InAt(0).AsRegister<Register>();
3303 Location value = locations->InAt(1);
3304
3305 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003306 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003307 Primitive::Type field_type = field_info.GetFieldType();
3308 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003309 bool needs_write_barrier =
3310 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003311
3312 if (is_volatile) {
3313 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3314 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003315
3316 switch (field_type) {
3317 case Primitive::kPrimBoolean:
3318 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003319 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003320 break;
3321 }
3322
3323 case Primitive::kPrimShort:
3324 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003325 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003326 break;
3327 }
3328
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003329 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003330 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003331 if (kPoisonHeapReferences && needs_write_barrier) {
3332 // Note that in the case where `value` is a null reference,
3333 // we do not enter this block, as a null reference does not
3334 // need poisoning.
3335 DCHECK_EQ(field_type, Primitive::kPrimNot);
3336 Register temp = locations->GetTemp(0).AsRegister<Register>();
3337 __ Mov(temp, value.AsRegister<Register>());
3338 __ PoisonHeapReference(temp);
3339 __ StoreToOffset(kStoreWord, temp, base, offset);
3340 } else {
3341 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3342 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003343 break;
3344 }
3345
3346 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003347 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003348 GenerateWideAtomicStore(base, offset,
3349 value.AsRegisterPairLow<Register>(),
3350 value.AsRegisterPairHigh<Register>(),
3351 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003352 locations->GetTemp(1).AsRegister<Register>(),
3353 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003354 } else {
3355 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003356 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003357 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003358 break;
3359 }
3360
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003361 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003362 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003363 break;
3364 }
3365
3366 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003367 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003368 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003369 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3370 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3371
3372 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3373
3374 GenerateWideAtomicStore(base, offset,
3375 value_reg_lo,
3376 value_reg_hi,
3377 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003378 locations->GetTemp(3).AsRegister<Register>(),
3379 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003380 } else {
3381 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003382 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003383 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003384 break;
3385 }
3386
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003387 case Primitive::kPrimVoid:
3388 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003389 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003390 }
Calin Juravle52c48962014-12-16 17:02:57 +00003391
Calin Juravle77520bc2015-01-12 18:45:46 +00003392 // Longs and doubles are handled in the switch.
3393 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3394 codegen_->MaybeRecordImplicitNullCheck(instruction);
3395 }
3396
3397 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3398 Register temp = locations->GetTemp(0).AsRegister<Register>();
3399 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003400 codegen_->MarkGCCard(
3401 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003402 }
3403
Calin Juravle52c48962014-12-16 17:02:57 +00003404 if (is_volatile) {
3405 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3406 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003407}
3408
Calin Juravle52c48962014-12-16 17:02:57 +00003409void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3410 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003411 LocationSummary* locations =
3412 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003413 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003414
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003415 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003416 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003417 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003418 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003419
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003420 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3421 locations->SetOut(Location::RequiresFpuRegister());
3422 } else {
3423 locations->SetOut(Location::RequiresRegister(),
3424 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3425 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003426 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00003427 // Arm encoding have some additional constraints for ldrexd/strexd:
3428 // - registers need to be consecutive
3429 // - the first register should be even but not R14.
3430 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3431 // enable Arm encoding.
3432 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3433 locations->AddTemp(Location::RequiresRegister());
3434 locations->AddTemp(Location::RequiresRegister());
3435 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003436}
3437
Calin Juravle52c48962014-12-16 17:02:57 +00003438void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
3439 const FieldInfo& field_info) {
3440 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003441
Calin Juravle52c48962014-12-16 17:02:57 +00003442 LocationSummary* locations = instruction->GetLocations();
3443 Register base = locations->InAt(0).AsRegister<Register>();
3444 Location out = locations->Out();
3445 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003446 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003447 Primitive::Type field_type = field_info.GetFieldType();
3448 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3449
3450 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003451 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003452 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003453 break;
3454 }
3455
3456 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003457 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003458 break;
3459 }
3460
3461 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003462 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003463 break;
3464 }
3465
3466 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003467 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003468 break;
3469 }
3470
3471 case Primitive::kPrimInt:
3472 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003473 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003474 break;
3475 }
3476
3477 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003478 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003479 GenerateWideAtomicLoad(base, offset,
3480 out.AsRegisterPairLow<Register>(),
3481 out.AsRegisterPairHigh<Register>());
3482 } else {
3483 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3484 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003485 break;
3486 }
3487
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003488 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003489 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003490 break;
3491 }
3492
3493 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003494 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003495 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003496 Register lo = locations->GetTemp(0).AsRegister<Register>();
3497 Register hi = locations->GetTemp(1).AsRegister<Register>();
3498 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003499 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003500 __ vmovdrr(out_reg, lo, hi);
3501 } else {
3502 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003503 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003504 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003505 break;
3506 }
3507
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003508 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003509 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003510 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003511 }
Calin Juravle52c48962014-12-16 17:02:57 +00003512
Calin Juravle77520bc2015-01-12 18:45:46 +00003513 // Doubles are handled in the switch.
3514 if (field_type != Primitive::kPrimDouble) {
3515 codegen_->MaybeRecordImplicitNullCheck(instruction);
3516 }
3517
Calin Juravle52c48962014-12-16 17:02:57 +00003518 if (is_volatile) {
3519 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3520 }
Roland Levillain4d027112015-07-01 15:41:14 +01003521
3522 if (field_type == Primitive::kPrimNot) {
3523 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3524 }
Calin Juravle52c48962014-12-16 17:02:57 +00003525}
3526
3527void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3528 HandleFieldSet(instruction, instruction->GetFieldInfo());
3529}
3530
3531void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003532 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003533}
3534
3535void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3536 HandleFieldGet(instruction, instruction->GetFieldInfo());
3537}
3538
3539void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3540 HandleFieldGet(instruction, instruction->GetFieldInfo());
3541}
3542
3543void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3544 HandleFieldGet(instruction, instruction->GetFieldInfo());
3545}
3546
3547void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3548 HandleFieldGet(instruction, instruction->GetFieldInfo());
3549}
3550
3551void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3552 HandleFieldSet(instruction, instruction->GetFieldInfo());
3553}
3554
3555void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003556 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003557}
3558
3559void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003560 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3561 ? LocationSummary::kCallOnSlowPath
3562 : LocationSummary::kNoCall;
3563 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00003564 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003565 if (instruction->HasUses()) {
3566 locations->SetOut(Location::SameAsFirstInput());
3567 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003568}
3569
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003570void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003571 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3572 return;
3573 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003574 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003575
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003576 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3577 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3578}
3579
3580void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003581 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003582 codegen_->AddSlowPath(slow_path);
3583
3584 LocationSummary* locations = instruction->GetLocations();
3585 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003586
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003587 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003588}
3589
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003590void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003591 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003592 GenerateImplicitNullCheck(instruction);
3593 } else {
3594 GenerateExplicitNullCheck(instruction);
3595 }
3596}
3597
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003598void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003599 LocationSummary* locations =
3600 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003601 locations->SetInAt(0, Location::RequiresRegister());
3602 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003603 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3604 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3605 } else {
3606 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3607 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003608}
3609
3610void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3611 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003612 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003613 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003614 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003615
Roland Levillain4d027112015-07-01 15:41:14 +01003616 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003617 case Primitive::kPrimBoolean: {
3618 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003619 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003620 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003621 size_t offset =
3622 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003623 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3624 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003625 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003626 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3627 }
3628 break;
3629 }
3630
3631 case Primitive::kPrimByte: {
3632 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003633 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003634 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003635 size_t offset =
3636 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003637 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3638 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003639 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003640 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3641 }
3642 break;
3643 }
3644
3645 case Primitive::kPrimShort: {
3646 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003647 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003648 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003649 size_t offset =
3650 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003651 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3652 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003653 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003654 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3655 }
3656 break;
3657 }
3658
3659 case Primitive::kPrimChar: {
3660 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003661 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003662 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003663 size_t offset =
3664 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003665 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3666 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003667 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003668 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3669 }
3670 break;
3671 }
3672
3673 case Primitive::kPrimInt:
3674 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003675 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3676 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003677 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003678 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003679 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003680 size_t offset =
3681 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003682 __ LoadFromOffset(kLoadWord, out, obj, offset);
3683 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003684 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003685 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3686 }
3687 break;
3688 }
3689
3690 case Primitive::kPrimLong: {
3691 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003692 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003693 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003694 size_t offset =
3695 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003696 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003697 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003698 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003699 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003700 }
3701 break;
3702 }
3703
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003704 case Primitive::kPrimFloat: {
3705 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3706 Location out = locations->Out();
3707 DCHECK(out.IsFpuRegister());
3708 if (index.IsConstant()) {
3709 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3710 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3711 } else {
3712 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3713 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3714 }
3715 break;
3716 }
3717
3718 case Primitive::kPrimDouble: {
3719 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3720 Location out = locations->Out();
3721 DCHECK(out.IsFpuRegisterPair());
3722 if (index.IsConstant()) {
3723 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3724 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3725 } else {
3726 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3727 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3728 }
3729 break;
3730 }
3731
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003732 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01003733 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003734 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003735 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003736 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01003737
3738 if (type == Primitive::kPrimNot) {
3739 Register out = locations->Out().AsRegister<Register>();
3740 __ MaybeUnpoisonHeapReference(out);
3741 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003742}
3743
3744void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003745 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003746
3747 bool needs_write_barrier =
3748 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3749 bool needs_runtime_call = instruction->NeedsTypeCheck();
3750
Nicolas Geoffray39468442014-09-02 15:17:15 +01003751 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003752 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3753 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003754 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003755 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3756 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3757 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003758 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003759 locations->SetInAt(0, Location::RequiresRegister());
3760 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003761 if (Primitive::IsFloatingPointType(value_type)) {
3762 locations->SetInAt(2, Location::RequiresFpuRegister());
3763 } else {
3764 locations->SetInAt(2, Location::RequiresRegister());
3765 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003766
3767 if (needs_write_barrier) {
3768 // Temporary registers for the write barrier.
Roland Levillain4d027112015-07-01 15:41:14 +01003769 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003770 locations->AddTemp(Location::RequiresRegister());
3771 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003772 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003773}
3774
3775void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3776 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003777 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003778 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003779 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003780 bool needs_runtime_call = locations->WillCall();
3781 bool needs_write_barrier =
3782 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003783
3784 switch (value_type) {
3785 case Primitive::kPrimBoolean:
3786 case Primitive::kPrimByte: {
3787 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003788 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003789 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003790 size_t offset =
3791 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003792 __ StoreToOffset(kStoreByte, value, obj, offset);
3793 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003794 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003795 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3796 }
3797 break;
3798 }
3799
3800 case Primitive::kPrimShort:
3801 case Primitive::kPrimChar: {
3802 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003803 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003804 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003805 size_t offset =
3806 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003807 __ StoreToOffset(kStoreHalfword, value, obj, offset);
3808 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003809 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003810 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3811 }
3812 break;
3813 }
3814
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003815 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003816 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003817 if (!needs_runtime_call) {
3818 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003819 Register value = locations->InAt(2).AsRegister<Register>();
Roland Levillain4d027112015-07-01 15:41:14 +01003820 Register source = value;
3821 if (kPoisonHeapReferences && needs_write_barrier) {
3822 // Note that in the case where `value` is a null reference,
3823 // we do not enter this block, as a null reference does not
3824 // need poisoning.
3825 DCHECK_EQ(value_type, Primitive::kPrimNot);
3826 Register temp = locations->GetTemp(0).AsRegister<Register>();
3827 __ Mov(temp, value);
3828 __ PoisonHeapReference(temp);
3829 source = temp;
3830 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003831 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003832 size_t offset =
3833 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillain4d027112015-07-01 15:41:14 +01003834 __ StoreToOffset(kStoreWord, source, obj, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003835 } else {
3836 DCHECK(index.IsRegister()) << index;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003837 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01003838 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003839 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003840 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003841 if (needs_write_barrier) {
3842 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003843 Register temp = locations->GetTemp(0).AsRegister<Register>();
3844 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003845 codegen_->MarkGCCard(temp, card, obj, value, instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003846 }
3847 } else {
3848 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain4d027112015-07-01 15:41:14 +01003849 // Note: if heap poisoning is enabled, pAputObject takes cares
3850 // of poisoning the reference.
Roland Levillain199f3362014-11-27 17:15:16 +00003851 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
3852 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003853 instruction->GetDexPc(),
3854 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003855 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003856 break;
3857 }
3858
3859 case Primitive::kPrimLong: {
3860 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003861 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003862 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003863 size_t offset =
3864 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003865 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003866 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003867 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003868 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003869 }
3870 break;
3871 }
3872
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003873 case Primitive::kPrimFloat: {
3874 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3875 Location value = locations->InAt(2);
3876 DCHECK(value.IsFpuRegister());
3877 if (index.IsConstant()) {
3878 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3879 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
3880 } else {
3881 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3882 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
3883 }
3884 break;
3885 }
3886
3887 case Primitive::kPrimDouble: {
3888 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3889 Location value = locations->InAt(2);
3890 DCHECK(value.IsFpuRegisterPair());
3891 if (index.IsConstant()) {
3892 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3893 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3894 } else {
3895 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3896 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3897 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003898
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003899 break;
3900 }
3901
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003902 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003903 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003904 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003905 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003906
3907 // Ints and objects are handled in the switch.
3908 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
3909 codegen_->MaybeRecordImplicitNullCheck(instruction);
3910 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003911}
3912
3913void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003914 LocationSummary* locations =
3915 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003916 locations->SetInAt(0, Location::RequiresRegister());
3917 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003918}
3919
3920void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
3921 LocationSummary* locations = instruction->GetLocations();
3922 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003923 Register obj = locations->InAt(0).AsRegister<Register>();
3924 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003925 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003926 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003927}
3928
3929void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003930 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3931 ? LocationSummary::kCallOnSlowPath
3932 : LocationSummary::kNoCall;
3933 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003934 locations->SetInAt(0, Location::RequiresRegister());
3935 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003936 if (instruction->HasUses()) {
3937 locations->SetOut(Location::SameAsFirstInput());
3938 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003939}
3940
3941void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3942 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07003943 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01003944 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003945 codegen_->AddSlowPath(slow_path);
3946
Roland Levillain271ab9c2014-11-27 15:23:57 +00003947 Register index = locations->InAt(0).AsRegister<Register>();
3948 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003949
3950 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01003951 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003952}
3953
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003954void CodeGeneratorARM::MarkGCCard(Register temp,
3955 Register card,
3956 Register object,
3957 Register value,
3958 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003959 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003960 if (can_be_null) {
3961 __ CompareAndBranchIfZero(value, &is_null);
3962 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003963 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
3964 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
3965 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003966 if (can_be_null) {
3967 __ Bind(&is_null);
3968 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003969}
3970
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003971void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
3972 temp->SetLocations(nullptr);
3973}
3974
3975void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
3976 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003977 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003978}
3979
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003980void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003981 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003982 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003983}
3984
3985void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003986 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3987}
3988
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003989void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3990 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3991}
3992
3993void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003994 HBasicBlock* block = instruction->GetBlock();
3995 if (block->GetLoopInformation() != nullptr) {
3996 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3997 // The back edge will generate the suspend check.
3998 return;
3999 }
4000 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4001 // The goto will generate the suspend check.
4002 return;
4003 }
4004 GenerateSuspendCheck(instruction, nullptr);
4005}
4006
4007void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4008 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004009 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004010 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4011 if (slow_path == nullptr) {
4012 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4013 instruction->SetSlowPath(slow_path);
4014 codegen_->AddSlowPath(slow_path);
4015 if (successor != nullptr) {
4016 DCHECK(successor->IsLoopHeader());
4017 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4018 }
4019 } else {
4020 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4021 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004022
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004023 __ LoadFromOffset(
4024 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004025 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004026 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004027 __ Bind(slow_path->GetReturnLabel());
4028 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004029 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004030 __ b(slow_path->GetEntryLabel());
4031 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004032}
4033
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004034ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4035 return codegen_->GetAssembler();
4036}
4037
4038void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004039 DCHECK_LT(index, moves_.size());
4040 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004041 Location source = move->GetSource();
4042 Location destination = move->GetDestination();
4043
4044 if (source.IsRegister()) {
4045 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004046 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004047 } else {
4048 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004049 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004050 SP, destination.GetStackIndex());
4051 }
4052 } else if (source.IsStackSlot()) {
4053 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004054 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004055 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004056 } else if (destination.IsFpuRegister()) {
4057 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004058 } else {
4059 DCHECK(destination.IsStackSlot());
4060 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4061 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4062 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004063 } else if (source.IsFpuRegister()) {
4064 if (destination.IsFpuRegister()) {
4065 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004066 } else {
4067 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004068 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4069 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004070 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004071 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004072 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4073 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004074 } else if (destination.IsRegisterPair()) {
4075 DCHECK(ExpectedPairLayout(destination));
4076 __ LoadFromOffset(
4077 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4078 } else {
4079 DCHECK(destination.IsFpuRegisterPair()) << destination;
4080 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4081 SP,
4082 source.GetStackIndex());
4083 }
4084 } else if (source.IsRegisterPair()) {
4085 if (destination.IsRegisterPair()) {
4086 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4087 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4088 } else {
4089 DCHECK(destination.IsDoubleStackSlot()) << destination;
4090 DCHECK(ExpectedPairLayout(source));
4091 __ StoreToOffset(
4092 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4093 }
4094 } else if (source.IsFpuRegisterPair()) {
4095 if (destination.IsFpuRegisterPair()) {
4096 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4097 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4098 } else {
4099 DCHECK(destination.IsDoubleStackSlot()) << destination;
4100 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4101 SP,
4102 destination.GetStackIndex());
4103 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004104 } else {
4105 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004106 HConstant* constant = source.GetConstant();
4107 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4108 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004109 if (destination.IsRegister()) {
4110 __ LoadImmediate(destination.AsRegister<Register>(), value);
4111 } else {
4112 DCHECK(destination.IsStackSlot());
4113 __ LoadImmediate(IP, value);
4114 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4115 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004116 } else if (constant->IsLongConstant()) {
4117 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004118 if (destination.IsRegisterPair()) {
4119 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4120 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004121 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004122 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004123 __ LoadImmediate(IP, Low32Bits(value));
4124 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4125 __ LoadImmediate(IP, High32Bits(value));
4126 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4127 }
4128 } else if (constant->IsDoubleConstant()) {
4129 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004130 if (destination.IsFpuRegisterPair()) {
4131 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004132 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004133 DCHECK(destination.IsDoubleStackSlot()) << destination;
4134 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004135 __ LoadImmediate(IP, Low32Bits(int_value));
4136 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4137 __ LoadImmediate(IP, High32Bits(int_value));
4138 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4139 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004140 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004141 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004142 float value = constant->AsFloatConstant()->GetValue();
4143 if (destination.IsFpuRegister()) {
4144 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4145 } else {
4146 DCHECK(destination.IsStackSlot());
4147 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4148 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4149 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004150 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004151 }
4152}
4153
4154void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4155 __ Mov(IP, reg);
4156 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4157 __ StoreToOffset(kStoreWord, IP, SP, mem);
4158}
4159
4160void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4161 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4162 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4163 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4164 SP, mem1 + stack_offset);
4165 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4166 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4167 SP, mem2 + stack_offset);
4168 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
4169}
4170
4171void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004172 DCHECK_LT(index, moves_.size());
4173 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004174 Location source = move->GetSource();
4175 Location destination = move->GetDestination();
4176
4177 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004178 DCHECK_NE(source.AsRegister<Register>(), IP);
4179 DCHECK_NE(destination.AsRegister<Register>(), IP);
4180 __ Mov(IP, source.AsRegister<Register>());
4181 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
4182 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004183 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004184 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004185 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004186 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004187 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4188 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004189 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004190 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004191 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004192 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004193 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004194 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004195 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004196 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004197 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4198 destination.AsRegisterPairHigh<Register>(),
4199 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004200 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004201 Register low_reg = source.IsRegisterPair()
4202 ? source.AsRegisterPairLow<Register>()
4203 : destination.AsRegisterPairLow<Register>();
4204 int mem = source.IsRegisterPair()
4205 ? destination.GetStackIndex()
4206 : source.GetStackIndex();
4207 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004208 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004209 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004210 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004211 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004212 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
4213 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004214 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004215 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004216 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004217 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
4218 DRegister reg = source.IsFpuRegisterPair()
4219 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
4220 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
4221 int mem = source.IsFpuRegisterPair()
4222 ? destination.GetStackIndex()
4223 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004224 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004225 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004226 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004227 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
4228 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
4229 : destination.AsFpuRegister<SRegister>();
4230 int mem = source.IsFpuRegister()
4231 ? destination.GetStackIndex()
4232 : source.GetStackIndex();
4233
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004234 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004235 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004236 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004237 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004238 Exchange(source.GetStackIndex(), destination.GetStackIndex());
4239 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004240 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004241 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004242 }
4243}
4244
4245void ParallelMoveResolverARM::SpillScratch(int reg) {
4246 __ Push(static_cast<Register>(reg));
4247}
4248
4249void ParallelMoveResolverARM::RestoreScratch(int reg) {
4250 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004251}
4252
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004253void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004254 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4255 ? LocationSummary::kCallOnSlowPath
4256 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004257 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004258 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004259 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004260 locations->SetOut(Location::RequiresRegister());
4261}
4262
4263void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004264 LocationSummary* locations = cls->GetLocations();
4265 Register out = locations->Out().AsRegister<Register>();
4266 Register current_method = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004267 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004268 DCHECK(!cls->CanCallRuntime());
4269 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004270 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004271 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004272 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004273 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004274 __ LoadFromOffset(kLoadWord,
4275 out,
4276 current_method,
Vladimir Marko05792b92015-08-03 11:56:49 +01004277 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004278 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004279 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004280
Andreas Gampe85b62f22015-09-09 13:15:38 -07004281 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004282 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4283 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004284 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004285 if (cls->MustGenerateClinitCheck()) {
4286 GenerateClassInitializationCheck(slow_path, out);
4287 } else {
4288 __ Bind(slow_path->GetExitLabel());
4289 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004290 }
4291}
4292
4293void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
4294 LocationSummary* locations =
4295 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4296 locations->SetInAt(0, Location::RequiresRegister());
4297 if (check->HasUses()) {
4298 locations->SetOut(Location::SameAsFirstInput());
4299 }
4300}
4301
4302void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004303 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07004304 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004305 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004306 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004307 GenerateClassInitializationCheck(slow_path,
4308 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004309}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004310
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004311void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07004312 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004313 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
4314 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
4315 __ b(slow_path->GetEntryLabel(), LT);
4316 // Even if the initialized flag is set, we may be in a situation where caches are not synced
4317 // properly. Therefore, we do a memory fence.
4318 __ dmb(ISH);
4319 __ Bind(slow_path->GetExitLabel());
4320}
4321
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004322void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
4323 LocationSummary* locations =
4324 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004325 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004326 locations->SetOut(Location::RequiresRegister());
4327}
4328
4329void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004330 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004331 codegen_->AddSlowPath(slow_path);
4332
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004333 LocationSummary* locations = load->GetLocations();
4334 Register out = locations->Out().AsRegister<Register>();
4335 Register current_method = locations->InAt(0).AsRegister<Register>();
4336 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004337 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Mathieu Chartiereace4582014-11-24 18:29:54 -08004338 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004339 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004340 // TODO: We will need a read barrier here.
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004341 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004342 __ Bind(slow_path->GetExitLabel());
4343}
4344
David Brazdilcb1c0552015-08-04 16:22:25 +01004345static int32_t GetExceptionTlsOffset() {
4346 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
4347}
4348
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004349void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
4350 LocationSummary* locations =
4351 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4352 locations->SetOut(Location::RequiresRegister());
4353}
4354
4355void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004356 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01004357 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
4358}
4359
4360void LocationsBuilderARM::VisitClearException(HClearException* clear) {
4361 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4362}
4363
4364void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004365 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01004366 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004367}
4368
4369void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
4370 LocationSummary* locations =
4371 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4372 InvokeRuntimeCallingConvention calling_convention;
4373 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4374}
4375
4376void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
4377 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004378 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004379}
4380
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004381void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004382 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4383 switch (instruction->GetTypeCheckKind()) {
4384 case TypeCheckKind::kExactCheck:
4385 case TypeCheckKind::kAbstractClassCheck:
4386 case TypeCheckKind::kClassHierarchyCheck:
4387 case TypeCheckKind::kArrayObjectCheck:
4388 call_kind = LocationSummary::kNoCall;
4389 break;
4390 case TypeCheckKind::kInterfaceCheck:
4391 call_kind = LocationSummary::kCall;
4392 break;
4393 case TypeCheckKind::kArrayCheck:
4394 call_kind = LocationSummary::kCallOnSlowPath;
4395 break;
4396 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004397 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004398 if (call_kind != LocationSummary::kCall) {
4399 locations->SetInAt(0, Location::RequiresRegister());
4400 locations->SetInAt(1, Location::RequiresRegister());
4401 // The out register is used as a temporary, so it overlaps with the inputs.
4402 // Note that TypeCheckSlowPathARM uses this register too.
4403 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4404 } else {
4405 InvokeRuntimeCallingConvention calling_convention;
4406 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4407 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4408 locations->SetOut(Location::RegisterLocation(R0));
4409 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004410}
4411
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004412void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004413 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004414 Register obj = locations->InAt(0).AsRegister<Register>();
4415 Register cls = locations->InAt(1).AsRegister<Register>();
4416 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004417 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004418 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4419 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4420 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004421 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07004422 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004423
4424 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004425 // avoid null check if we know obj is not null.
4426 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00004427 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004428 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004429
4430 // In case of an interface check, we put the object class into the object register.
4431 // This is safe, as the register is caller-save, and the object must be in another
4432 // register if it survives the runtime call.
4433 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck)
4434 ? obj
4435 : out;
4436 __ LoadFromOffset(kLoadWord, target, obj, class_offset);
4437 __ MaybeUnpoisonHeapReference(target);
4438
4439 switch (instruction->GetTypeCheckKind()) {
4440 case TypeCheckKind::kExactCheck: {
4441 __ cmp(out, ShifterOperand(cls));
4442 // Classes must be equal for the instanceof to succeed.
4443 __ b(&zero, NE);
4444 __ LoadImmediate(out, 1);
4445 __ b(&done);
4446 break;
4447 }
4448 case TypeCheckKind::kAbstractClassCheck: {
4449 // If the class is abstract, we eagerly fetch the super class of the
4450 // object to avoid doing a comparison we know will fail.
4451 Label loop;
4452 __ Bind(&loop);
4453 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4454 __ MaybeUnpoisonHeapReference(out);
4455 // If `out` is null, we use it for the result, and jump to `done`.
4456 __ CompareAndBranchIfZero(out, &done);
4457 __ cmp(out, ShifterOperand(cls));
4458 __ b(&loop, NE);
4459 __ LoadImmediate(out, 1);
4460 if (zero.IsLinked()) {
4461 __ b(&done);
4462 }
4463 break;
4464 }
4465 case TypeCheckKind::kClassHierarchyCheck: {
4466 // Walk over the class hierarchy to find a match.
4467 Label loop, success;
4468 __ Bind(&loop);
4469 __ cmp(out, ShifterOperand(cls));
4470 __ b(&success, EQ);
4471 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4472 __ MaybeUnpoisonHeapReference(out);
4473 __ CompareAndBranchIfNonZero(out, &loop);
4474 // If `out` is null, we use it for the result, and jump to `done`.
4475 __ b(&done);
4476 __ Bind(&success);
4477 __ LoadImmediate(out, 1);
4478 if (zero.IsLinked()) {
4479 __ b(&done);
4480 }
4481 break;
4482 }
4483 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004484 // Do an exact check.
4485 Label exact_check;
4486 __ cmp(out, ShifterOperand(cls));
4487 __ b(&exact_check, EQ);
4488 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004489 __ LoadFromOffset(kLoadWord, out, out, component_offset);
4490 __ MaybeUnpoisonHeapReference(out);
4491 // If `out` is null, we use it for the result, and jump to `done`.
4492 __ CompareAndBranchIfZero(out, &done);
4493 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
4494 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4495 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004496 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004497 __ LoadImmediate(out, 1);
4498 __ b(&done);
4499 break;
4500 }
4501 case TypeCheckKind::kArrayCheck: {
4502 __ cmp(out, ShifterOperand(cls));
4503 DCHECK(locations->OnlyCallsOnSlowPath());
4504 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4505 instruction, /* is_fatal */ false);
4506 codegen_->AddSlowPath(slow_path);
4507 __ b(slow_path->GetEntryLabel(), NE);
4508 __ LoadImmediate(out, 1);
4509 if (zero.IsLinked()) {
4510 __ b(&done);
4511 }
4512 break;
4513 }
4514
4515 case TypeCheckKind::kInterfaceCheck:
4516 default: {
4517 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
4518 instruction,
4519 instruction->GetDexPc(),
4520 nullptr);
4521 if (zero.IsLinked()) {
4522 __ b(&done);
4523 }
4524 break;
4525 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004526 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004527
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004528 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004529 __ Bind(&zero);
4530 __ LoadImmediate(out, 0);
4531 }
4532
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004533 if (done.IsLinked()) {
4534 __ Bind(&done);
4535 }
4536
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004537 if (slow_path != nullptr) {
4538 __ Bind(slow_path->GetExitLabel());
4539 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004540}
4541
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004542void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004543 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4544 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
4545
4546 switch (instruction->GetTypeCheckKind()) {
4547 case TypeCheckKind::kExactCheck:
4548 case TypeCheckKind::kAbstractClassCheck:
4549 case TypeCheckKind::kClassHierarchyCheck:
4550 case TypeCheckKind::kArrayObjectCheck:
4551 call_kind = throws_into_catch
4552 ? LocationSummary::kCallOnSlowPath
4553 : LocationSummary::kNoCall;
4554 break;
4555 case TypeCheckKind::kInterfaceCheck:
4556 call_kind = LocationSummary::kCall;
4557 break;
4558 case TypeCheckKind::kArrayCheck:
4559 call_kind = LocationSummary::kCallOnSlowPath;
4560 break;
4561 }
4562
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004563 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004564 instruction, call_kind);
4565 if (call_kind != LocationSummary::kCall) {
4566 locations->SetInAt(0, Location::RequiresRegister());
4567 locations->SetInAt(1, Location::RequiresRegister());
4568 // Note that TypeCheckSlowPathARM uses this register too.
4569 locations->AddTemp(Location::RequiresRegister());
4570 } else {
4571 InvokeRuntimeCallingConvention calling_convention;
4572 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4573 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4574 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004575}
4576
4577void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
4578 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004579 Register obj = locations->InAt(0).AsRegister<Register>();
4580 Register cls = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004581 Register temp = locations->WillCall()
4582 ? Register(kNoRegister)
4583 : locations->GetTemp(0).AsRegister<Register>();
4584
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004585 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004586 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4587 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4588 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
4589 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004590
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004591 if (!locations->WillCall()) {
4592 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4593 instruction, !locations->CanCall());
4594 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray64acf302015-09-14 22:20:29 +01004595 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004596
4597 Label done;
4598 // Avoid null check if we know obj is not null.
4599 if (instruction->MustDoNullCheck()) {
4600 __ CompareAndBranchIfZero(obj, &done);
4601 }
4602
4603 if (locations->WillCall()) {
4604 __ LoadFromOffset(kLoadWord, obj, obj, class_offset);
4605 __ MaybeUnpoisonHeapReference(obj);
4606 } else {
4607 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
4608 __ MaybeUnpoisonHeapReference(temp);
4609 }
4610
4611 switch (instruction->GetTypeCheckKind()) {
4612 case TypeCheckKind::kExactCheck:
4613 case TypeCheckKind::kArrayCheck: {
4614 __ cmp(temp, ShifterOperand(cls));
4615 // Jump to slow path for throwing the exception or doing a
4616 // more involved array check.
4617 __ b(slow_path->GetEntryLabel(), NE);
4618 break;
4619 }
4620 case TypeCheckKind::kAbstractClassCheck: {
4621 // If the class is abstract, we eagerly fetch the super class of the
4622 // object to avoid doing a comparison we know will fail.
4623 Label loop;
4624 __ Bind(&loop);
4625 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
4626 __ MaybeUnpoisonHeapReference(temp);
4627 // Jump to the slow path to throw the exception.
4628 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
4629 __ cmp(temp, ShifterOperand(cls));
4630 __ b(&loop, NE);
4631 break;
4632 }
4633 case TypeCheckKind::kClassHierarchyCheck: {
4634 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004635 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004636 __ Bind(&loop);
4637 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004638 __ b(&done, EQ);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004639 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
4640 __ MaybeUnpoisonHeapReference(temp);
4641 __ CompareAndBranchIfNonZero(temp, &loop);
4642 // Jump to the slow path to throw the exception.
4643 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004644 break;
4645 }
4646 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004647 // Do an exact check.
4648 __ cmp(temp, ShifterOperand(cls));
4649 __ b(&done, EQ);
4650 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004651 __ LoadFromOffset(kLoadWord, temp, temp, component_offset);
4652 __ MaybeUnpoisonHeapReference(temp);
4653 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
4654 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
4655 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4656 __ CompareAndBranchIfNonZero(temp, slow_path->GetEntryLabel());
4657 break;
4658 }
4659 case TypeCheckKind::kInterfaceCheck:
4660 default:
4661 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
4662 instruction,
4663 instruction->GetDexPc(),
4664 nullptr);
4665 break;
4666 }
4667 __ Bind(&done);
4668
4669 if (slow_path != nullptr) {
4670 __ Bind(slow_path->GetExitLabel());
4671 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004672}
4673
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004674void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4675 LocationSummary* locations =
4676 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4677 InvokeRuntimeCallingConvention calling_convention;
4678 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4679}
4680
4681void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4682 codegen_->InvokeRuntime(instruction->IsEnter()
4683 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
4684 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004685 instruction->GetDexPc(),
4686 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004687}
4688
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004689void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4690void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4691void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4692
4693void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4694 LocationSummary* locations =
4695 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4696 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4697 || instruction->GetResultType() == Primitive::kPrimLong);
4698 locations->SetInAt(0, Location::RequiresRegister());
4699 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004700 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004701}
4702
4703void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
4704 HandleBitwiseOperation(instruction);
4705}
4706
4707void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
4708 HandleBitwiseOperation(instruction);
4709}
4710
4711void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
4712 HandleBitwiseOperation(instruction);
4713}
4714
4715void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4716 LocationSummary* locations = instruction->GetLocations();
4717
4718 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004719 Register first = locations->InAt(0).AsRegister<Register>();
4720 Register second = locations->InAt(1).AsRegister<Register>();
4721 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004722 if (instruction->IsAnd()) {
4723 __ and_(out, first, ShifterOperand(second));
4724 } else if (instruction->IsOr()) {
4725 __ orr(out, first, ShifterOperand(second));
4726 } else {
4727 DCHECK(instruction->IsXor());
4728 __ eor(out, first, ShifterOperand(second));
4729 }
4730 } else {
4731 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4732 Location first = locations->InAt(0);
4733 Location second = locations->InAt(1);
4734 Location out = locations->Out();
4735 if (instruction->IsAnd()) {
4736 __ and_(out.AsRegisterPairLow<Register>(),
4737 first.AsRegisterPairLow<Register>(),
4738 ShifterOperand(second.AsRegisterPairLow<Register>()));
4739 __ and_(out.AsRegisterPairHigh<Register>(),
4740 first.AsRegisterPairHigh<Register>(),
4741 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4742 } else if (instruction->IsOr()) {
4743 __ orr(out.AsRegisterPairLow<Register>(),
4744 first.AsRegisterPairLow<Register>(),
4745 ShifterOperand(second.AsRegisterPairLow<Register>()));
4746 __ orr(out.AsRegisterPairHigh<Register>(),
4747 first.AsRegisterPairHigh<Register>(),
4748 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4749 } else {
4750 DCHECK(instruction->IsXor());
4751 __ eor(out.AsRegisterPairLow<Register>(),
4752 first.AsRegisterPairLow<Register>(),
4753 ShifterOperand(second.AsRegisterPairLow<Register>()));
4754 __ eor(out.AsRegisterPairHigh<Register>(),
4755 first.AsRegisterPairHigh<Register>(),
4756 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4757 }
4758 }
4759}
4760
Nicolas Geoffray38207af2015-06-01 15:46:22 +01004761void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00004762 // For better instruction scheduling we load the direct code pointer before the method pointer.
4763 bool direct_code_loaded = false;
4764 switch (invoke->GetCodePtrLocation()) {
4765 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4766 if (IsSameDexFile(*invoke->GetTargetMethod().dex_file, GetGraph()->GetDexFile())) {
4767 break;
4768 }
4769 // Calls across dex files are more likely to exceed the available BL range,
4770 // so use absolute patch by falling through to kDirectCodeFixup.
4771 FALLTHROUGH_INTENDED;
4772 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4773 // LR = code address from literal pool with link-time patch.
4774 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
4775 direct_code_loaded = true;
4776 break;
4777 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4778 // LR = invoke->GetDirectCodePtr();
4779 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
4780 direct_code_loaded = true;
4781 break;
4782 default:
4783 break;
4784 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004785
Vladimir Marko58155012015-08-19 12:49:41 +00004786 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
4787 switch (invoke->GetMethodLoadKind()) {
4788 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
4789 // temp = thread->string_init_entrypoint
4790 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
4791 break;
4792 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
4793 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
4794 break;
4795 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
4796 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
4797 break;
4798 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
4799 __ LoadLiteral(temp.AsRegister<Register>(),
4800 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
4801 break;
4802 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
4803 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
4804 FALLTHROUGH_INTENDED;
4805 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
4806 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
4807 Register method_reg;
4808 Register reg = temp.AsRegister<Register>();
4809 if (current_method.IsRegister()) {
4810 method_reg = current_method.AsRegister<Register>();
4811 } else {
4812 DCHECK(invoke->GetLocations()->Intrinsified());
4813 DCHECK(!current_method.IsValid());
4814 method_reg = reg;
4815 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
4816 }
4817 // temp = current_method->dex_cache_resolved_methods_;
4818 __ LoadFromOffset(
Vladimir Marko05792b92015-08-03 11:56:49 +01004819 kLoadWord, reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset(
4820 kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00004821 // temp = temp[index_in_cache]
4822 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
4823 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
4824 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01004825 }
Vladimir Marko58155012015-08-19 12:49:41 +00004826 }
4827
4828 switch (invoke->GetCodePtrLocation()) {
4829 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
4830 __ bl(GetFrameEntryLabel());
4831 break;
4832 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
4833 if (!direct_code_loaded) {
4834 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
4835 __ Bind(&relative_call_patches_.back().label);
4836 Label label;
4837 __ bl(&label); // Arbitrarily branch to the instruction after BL, override at link time.
4838 __ Bind(&label);
4839 break;
4840 }
4841 // If we loaded the direct code above, fall through.
4842 FALLTHROUGH_INTENDED;
4843 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4844 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4845 // LR prepared above for better instruction scheduling.
4846 DCHECK(direct_code_loaded);
4847 // LR()
4848 __ blx(LR);
4849 break;
4850 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
4851 // LR = callee_method->entry_point_from_quick_compiled_code_
4852 __ LoadFromOffset(
4853 kLoadWord, LR, callee_method.AsRegister<Register>(),
4854 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
4855 // LR()
4856 __ blx(LR);
4857 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004858 }
4859
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004860 DCHECK(!IsLeafMethod());
4861}
4862
Andreas Gampebfb5ba92015-09-01 15:45:02 +00004863void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
4864 Register temp = temp_location.AsRegister<Register>();
4865 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
4866 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
4867 LocationSummary* locations = invoke->GetLocations();
4868 Location receiver = locations->InAt(0);
4869 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4870 // temp = object->GetClass();
4871 DCHECK(receiver.IsRegister());
4872 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
4873 MaybeRecordImplicitNullCheck(invoke);
4874 __ MaybeUnpoisonHeapReference(temp);
4875 // temp = temp->GetMethodAt(method_offset);
4876 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
4877 kArmWordSize).Int32Value();
4878 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
4879 // LR = temp->GetEntryPoint();
4880 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
4881 // LR();
4882 __ blx(LR);
4883}
4884
Vladimir Marko58155012015-08-19 12:49:41 +00004885void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
4886 DCHECK(linker_patches->empty());
4887 size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
4888 linker_patches->reserve(size);
4889 for (const auto& entry : method_patches_) {
4890 const MethodReference& target_method = entry.first;
4891 Literal* literal = entry.second;
4892 DCHECK(literal->GetLabel()->IsBound());
4893 uint32_t literal_offset = literal->GetLabel()->Position();
4894 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
4895 target_method.dex_file,
4896 target_method.dex_method_index));
4897 }
4898 for (const auto& entry : call_patches_) {
4899 const MethodReference& target_method = entry.first;
4900 Literal* literal = entry.second;
4901 DCHECK(literal->GetLabel()->IsBound());
4902 uint32_t literal_offset = literal->GetLabel()->Position();
4903 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
4904 target_method.dex_file,
4905 target_method.dex_method_index));
4906 }
4907 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
4908 uint32_t literal_offset = info.label.Position();
4909 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
4910 info.target_method.dex_file,
4911 info.target_method.dex_method_index));
4912 }
4913}
4914
4915Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
4916 MethodToLiteralMap* map) {
4917 // Look up the literal for target_method.
4918 auto lb = map->lower_bound(target_method);
4919 if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
4920 return lb->second;
4921 }
4922 // We don't have a literal for this method yet, insert a new one.
4923 Literal* literal = __ NewLiteral<uint32_t>(0u);
4924 map->PutBefore(lb, target_method, literal);
4925 return literal;
4926}
4927
4928Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
4929 return DeduplicateMethodLiteral(target_method, &method_patches_);
4930}
4931
4932Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
4933 return DeduplicateMethodLiteral(target_method, &call_patches_);
4934}
4935
Calin Juravleb1498f62015-02-16 13:13:29 +00004936void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
4937 // Nothing to do, this should be removed during prepare for register allocator.
4938 UNUSED(instruction);
4939 LOG(FATAL) << "Unreachable";
4940}
4941
4942void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
4943 // Nothing to do, this should be removed during prepare for register allocator.
4944 UNUSED(instruction);
4945 LOG(FATAL) << "Unreachable";
4946}
4947
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01004948void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
4949 DCHECK(codegen_->IsBaseline());
4950 LocationSummary* locations =
4951 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4952 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
4953}
4954
4955void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
4956 DCHECK(codegen_->IsBaseline());
4957 // Will be generated at use site.
4958}
4959
Mark Mendellfe57faa2015-09-18 09:26:15 -04004960// Simple implementation of packed switch - generate cascaded compare/jumps.
4961void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
4962 LocationSummary* locations =
4963 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
4964 locations->SetInAt(0, Location::RequiresRegister());
4965}
4966
4967void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
4968 int32_t lower_bound = switch_instr->GetStartValue();
4969 int32_t num_entries = switch_instr->GetNumEntries();
4970 LocationSummary* locations = switch_instr->GetLocations();
4971 Register value_reg = locations->InAt(0).AsRegister<Register>();
4972 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
4973
4974 // Create a series of compare/jumps.
4975 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
4976 for (int32_t i = 0; i < num_entries; i++) {
4977 GenerateCompareWithImmediate(value_reg, lower_bound + i);
4978 __ b(codegen_->GetLabelOf(successors.at(i)), EQ);
4979 }
4980
4981 // And the default for any other value.
4982 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
4983 __ b(codegen_->GetLabelOf(default_block));
4984 }
4985}
4986
Andreas Gampe85b62f22015-09-09 13:15:38 -07004987void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
4988 if (!trg.IsValid()) {
4989 DCHECK(type == Primitive::kPrimVoid);
4990 return;
4991 }
4992
4993 DCHECK_NE(type, Primitive::kPrimVoid);
4994
4995 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
4996 if (return_loc.Equals(trg)) {
4997 return;
4998 }
4999
5000 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
5001 // with the last branch.
5002 if (type == Primitive::kPrimLong) {
5003 HParallelMove parallel_move(GetGraph()->GetArena());
5004 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
5005 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
5006 GetMoveResolver()->EmitNativeCode(&parallel_move);
5007 } else if (type == Primitive::kPrimDouble) {
5008 HParallelMove parallel_move(GetGraph()->GetArena());
5009 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
5010 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
5011 GetMoveResolver()->EmitNativeCode(&parallel_move);
5012 } else {
5013 // Let the parallel move resolver take care of all of this.
5014 HParallelMove parallel_move(GetGraph()->GetArena());
5015 parallel_move.AddMove(return_loc, trg, type, nullptr);
5016 GetMoveResolver()->EmitNativeCode(&parallel_move);
5017 }
5018}
5019
Roland Levillain4d027112015-07-01 15:41:14 +01005020#undef __
5021#undef QUICK_ENTRY_POINT
5022
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00005023} // namespace arm
5024} // namespace art