blob: af2e2289347bf2b293b23f9a4e5b17ee6a152406 [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
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070059static constexpr uint32_t kPackedSwitchJumpTableThreshold = 6;
60
Roland Levillain62a46b22015-06-01 18:24:13 +010061#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010062#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010063
Andreas Gampe85b62f22015-09-09 13:15:38 -070064class NullCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010065 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010066 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010067
Alexandre Rames67555f72014-11-18 10:55:16 +000068 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010069 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010070 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000071 if (instruction_->CanThrowIntoCatchBlock()) {
72 // Live registers will be restored in the catch block if caught.
73 SaveLiveRegisters(codegen, instruction_->GetLocations());
74 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010075 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000076 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010077 }
78
Alexandre Rames8158f282015-08-07 10:26:17 +010079 bool IsFatal() const OVERRIDE { return true; }
80
Alexandre Rames9931f312015-06-19 14:47:01 +010081 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
82
Nicolas Geoffraye5038322014-07-04 09:41:32 +010083 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010084 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010085 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
86};
87
Andreas Gampe85b62f22015-09-09 13:15:38 -070088class DivZeroCheckSlowPathARM : public SlowPathCode {
Calin Juravled0d48522014-11-04 16:40:20 +000089 public:
90 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
91
Alexandre Rames67555f72014-11-18 10:55:16 +000092 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000093 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
94 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +000095 if (instruction_->CanThrowIntoCatchBlock()) {
96 // Live registers will be restored in the catch block if caught.
97 SaveLiveRegisters(codegen, instruction_->GetLocations());
98 }
Calin Juravled0d48522014-11-04 16:40:20 +000099 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000100 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
Calin Juravled0d48522014-11-04 16:40:20 +0000101 }
102
Alexandre Rames8158f282015-08-07 10:26:17 +0100103 bool IsFatal() const OVERRIDE { return true; }
104
Alexandre Rames9931f312015-06-19 14:47:01 +0100105 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
106
Calin Juravled0d48522014-11-04 16:40:20 +0000107 private:
108 HDivZeroCheck* const instruction_;
109 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
110};
111
Andreas Gampe85b62f22015-09-09 13:15:38 -0700112class SuspendCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000113 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000114 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100115 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000116
Alexandre Rames67555f72014-11-18 10:55:16 +0000117 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100118 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000119 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000120 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100121 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000122 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000123 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100124 if (successor_ == nullptr) {
125 __ b(GetReturnLabel());
126 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100127 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100128 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000129 }
130
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100131 Label* GetReturnLabel() {
132 DCHECK(successor_ == nullptr);
133 return &return_label_;
134 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000135
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100136 HBasicBlock* GetSuccessor() const {
137 return successor_;
138 }
139
Alexandre Rames9931f312015-06-19 14:47:01 +0100140 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
141
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000142 private:
143 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100144 // If not null, the block to branch to after the suspend check.
145 HBasicBlock* const successor_;
146
147 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000148 Label return_label_;
149
150 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
151};
152
Andreas Gampe85b62f22015-09-09 13:15:38 -0700153class BoundsCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100154 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100155 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
156 : instruction_(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100157
Alexandre Rames67555f72014-11-18 10:55:16 +0000158 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100159 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100160 LocationSummary* locations = instruction_->GetLocations();
161
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100162 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000163 if (instruction_->CanThrowIntoCatchBlock()) {
164 // Live registers will be restored in the catch block if caught.
165 SaveLiveRegisters(codegen, instruction_->GetLocations());
166 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000167 // We're moving two locations to locations that could overlap, so we need a parallel
168 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100169 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000170 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100171 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000172 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100173 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100174 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100175 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
176 Primitive::kPrimInt);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100177 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000178 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100179 }
180
Alexandre Rames8158f282015-08-07 10:26:17 +0100181 bool IsFatal() const OVERRIDE { return true; }
182
Alexandre Rames9931f312015-06-19 14:47:01 +0100183 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
184
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100185 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100186 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100187
188 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
189};
190
Andreas Gampe85b62f22015-09-09 13:15:38 -0700191class LoadClassSlowPathARM : public SlowPathCode {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100192 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000193 LoadClassSlowPathARM(HLoadClass* cls,
194 HInstruction* at,
195 uint32_t dex_pc,
196 bool do_clinit)
197 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
198 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
199 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100200
Alexandre Rames67555f72014-11-18 10:55:16 +0000201 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000202 LocationSummary* locations = at_->GetLocations();
203
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100204 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
205 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000206 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100207
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100208 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000209 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000210 int32_t entry_point_offset = do_clinit_
211 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
212 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000213 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000214
215 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000216 Location out = locations->Out();
217 if (out.IsValid()) {
218 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000219 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
220 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000221 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100222 __ b(GetExitLabel());
223 }
224
Alexandre Rames9931f312015-06-19 14:47:01 +0100225 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
226
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100227 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000228 // The class this slow path will load.
229 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100230
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000231 // The instruction where this slow path is happening.
232 // (Might be the load class or an initialization check).
233 HInstruction* const at_;
234
235 // The dex PC of `at_`.
236 const uint32_t dex_pc_;
237
238 // Whether to initialize the class.
239 const bool do_clinit_;
240
241 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100242};
243
Andreas Gampe85b62f22015-09-09 13:15:38 -0700244class LoadStringSlowPathARM : public SlowPathCode {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000245 public:
246 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
247
Alexandre Rames67555f72014-11-18 10:55:16 +0000248 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000249 LocationSummary* locations = instruction_->GetLocations();
250 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
251
252 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
253 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000254 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000255
256 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800257 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000258 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000259 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000260 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
261
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000262 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000263 __ b(GetExitLabel());
264 }
265
Alexandre Rames9931f312015-06-19 14:47:01 +0100266 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
267
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000268 private:
269 HLoadString* const instruction_;
270
271 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
272};
273
Andreas Gampe85b62f22015-09-09 13:15:38 -0700274class TypeCheckSlowPathARM : public SlowPathCode {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000275 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000276 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
277 : instruction_(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000278
Alexandre Rames67555f72014-11-18 10:55:16 +0000279 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000280 LocationSummary* locations = instruction_->GetLocations();
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100281 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0)
282 : locations->Out();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000283 DCHECK(instruction_->IsCheckCast()
284 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000285
286 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
287 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000288
289 if (instruction_->IsCheckCast()) {
290 // The codegen for the instruction overwrites `temp`, so put it back in place.
291 Register obj = locations->InAt(0).AsRegister<Register>();
292 Register temp = locations->GetTemp(0).AsRegister<Register>();
293 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
294 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
295 __ MaybeUnpoisonHeapReference(temp);
296 }
297
298 if (!is_fatal_) {
299 SaveLiveRegisters(codegen, locations);
300 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000301
302 // We're moving two locations to locations that could overlap, so we need a parallel
303 // move resolver.
304 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000305 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100306 locations->InAt(1),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000307 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100308 Primitive::kPrimNot,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100309 object_class,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100310 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
311 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000312
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000313 if (instruction_->IsInstanceOf()) {
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100314 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
315 instruction_,
316 instruction_->GetDexPc(),
317 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000318 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
319 } else {
320 DCHECK(instruction_->IsCheckCast());
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100321 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
322 instruction_,
323 instruction_->GetDexPc(),
324 this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000325 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000326
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000327 if (!is_fatal_) {
328 RestoreLiveRegisters(codegen, locations);
329 __ b(GetExitLabel());
330 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000331 }
332
Alexandre Rames9931f312015-06-19 14:47:01 +0100333 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
334
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000335 bool IsFatal() const OVERRIDE { return is_fatal_; }
336
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000337 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000338 HInstruction* const instruction_;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000339 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000340
341 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
342};
343
Andreas Gampe85b62f22015-09-09 13:15:38 -0700344class DeoptimizationSlowPathARM : public SlowPathCode {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700345 public:
346 explicit DeoptimizationSlowPathARM(HInstruction* instruction)
347 : instruction_(instruction) {}
348
349 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
350 __ Bind(GetEntryLabel());
351 SaveLiveRegisters(codegen, instruction_->GetLocations());
352 DCHECK(instruction_->IsDeoptimize());
353 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
354 uint32_t dex_pc = deoptimize->GetDexPc();
355 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
356 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
357 }
358
Alexandre Rames9931f312015-06-19 14:47:01 +0100359 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
360
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700361 private:
362 HInstruction* const instruction_;
363 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
364};
365
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100366class ArraySetSlowPathARM : public SlowPathCode {
367 public:
368 explicit ArraySetSlowPathARM(HInstruction* instruction) : instruction_(instruction) {}
369
370 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
371 LocationSummary* locations = instruction_->GetLocations();
372 __ Bind(GetEntryLabel());
373 SaveLiveRegisters(codegen, locations);
374
375 InvokeRuntimeCallingConvention calling_convention;
376 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
377 parallel_move.AddMove(
378 locations->InAt(0),
379 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
380 Primitive::kPrimNot,
381 nullptr);
382 parallel_move.AddMove(
383 locations->InAt(1),
384 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
385 Primitive::kPrimInt,
386 nullptr);
387 parallel_move.AddMove(
388 locations->InAt(2),
389 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
390 Primitive::kPrimNot,
391 nullptr);
392 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
393
394 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
395 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
396 instruction_,
397 instruction_->GetDexPc(),
398 this);
399 RestoreLiveRegisters(codegen, locations);
400 __ b(GetExitLabel());
401 }
402
403 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
404
405 private:
406 HInstruction* const instruction_;
407
408 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
409};
410
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000411#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100412#define __ down_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700413
Aart Bike9f37602015-10-09 11:15:55 -0700414inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700415 switch (cond) {
416 case kCondEQ: return EQ;
417 case kCondNE: return NE;
418 case kCondLT: return LT;
419 case kCondLE: return LE;
420 case kCondGT: return GT;
421 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -0700422 case kCondB: return LO;
423 case kCondBE: return LS;
424 case kCondA: return HI;
425 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700426 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100427 LOG(FATAL) << "Unreachable";
428 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700429}
430
Aart Bike9f37602015-10-09 11:15:55 -0700431// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100432inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700433 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100434 case kCondEQ: return EQ;
435 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -0700436 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +0100437 case kCondLT: return LO;
438 case kCondLE: return LS;
439 case kCondGT: return HI;
440 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -0700441 // Unsigned remain unchanged.
442 case kCondB: return LO;
443 case kCondBE: return LS;
444 case kCondA: return HI;
445 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -0700446 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100447 LOG(FATAL) << "Unreachable";
448 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700449}
450
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100451void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100452 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100453}
454
455void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100456 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100457}
458
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100459size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
460 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
461 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100462}
463
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100464size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
465 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
466 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100467}
468
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000469size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
470 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
471 return kArmWordSize;
472}
473
474size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
475 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
476 return kArmWordSize;
477}
478
Calin Juravle34166012014-12-19 17:22:29 +0000479CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000480 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100481 const CompilerOptions& compiler_options,
482 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000483 : CodeGenerator(graph,
484 kNumberOfCoreRegisters,
485 kNumberOfSRegisters,
486 kNumberOfRegisterPairs,
487 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
488 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +0000489 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
490 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100491 compiler_options,
492 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100493 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100494 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100495 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100496 move_resolver_(graph->GetArena(), this),
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000497 assembler_(),
Vladimir Marko58155012015-08-19 12:49:41 +0000498 isa_features_(isa_features),
Vladimir Marko5233f932015-09-29 19:01:15 +0100499 method_patches_(MethodReferenceComparator(),
500 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
501 call_patches_(MethodReferenceComparator(),
502 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
503 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -0700504 // Always save the LR register to mimic Quick.
505 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100506}
507
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000508void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
509 // Ensure that we fix up branches and literal loads and emit the literal pool.
510 __ FinalizeCode();
511
512 // Adjust native pc offsets in stack maps.
513 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
514 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
515 uint32_t new_position = __ GetAdjustedPosition(old_position);
516 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
517 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +0100518 // Adjust pc offsets for the disassembly information.
519 if (disasm_info_ != nullptr) {
520 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
521 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
522 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
523 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
524 it.second.start = __ GetAdjustedPosition(it.second.start);
525 it.second.end = __ GetAdjustedPosition(it.second.end);
526 }
527 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
528 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
529 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
530 }
531 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000532
533 CodeGenerator::Finalize(allocator);
534}
535
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100536Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100537 switch (type) {
538 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100539 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100540 ArmManagedRegister pair =
541 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100542 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
543 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
544
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100545 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
546 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100547 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100548 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100549 }
550
551 case Primitive::kPrimByte:
552 case Primitive::kPrimBoolean:
553 case Primitive::kPrimChar:
554 case Primitive::kPrimShort:
555 case Primitive::kPrimInt:
556 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100557 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100558 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100559 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
560 ArmManagedRegister current =
561 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
562 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100563 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100564 }
565 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100566 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100567 }
568
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000569 case Primitive::kPrimFloat: {
570 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100571 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100572 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100573
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000574 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000575 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
576 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000577 return Location::FpuRegisterPairLocation(reg, reg + 1);
578 }
579
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100580 case Primitive::kPrimVoid:
581 LOG(FATAL) << "Unreachable type " << type;
582 }
583
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100584 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100585}
586
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000587void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100588 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100589 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100590
591 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100592 blocked_core_registers_[SP] = true;
593 blocked_core_registers_[LR] = true;
594 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100595
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100596 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100597 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100598
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100599 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100600 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100601
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000602 if (is_baseline) {
603 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
604 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
605 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000606
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000607 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100608 }
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000609
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +0100610 if (is_baseline || GetGraph()->IsDebuggable()) {
611 // Stubs do not save callee-save floating point registers. If the graph
612 // is debuggable, we need to deal with these registers differently. For
613 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000614 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
615 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
616 }
617 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100618
619 UpdateBlockedPairRegisters();
620}
621
622void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
623 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
624 ArmManagedRegister current =
625 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
626 if (blocked_core_registers_[current.AsRegisterPairLow()]
627 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
628 blocked_register_pairs_[i] = true;
629 }
630 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100631}
632
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100633InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
634 : HGraphVisitor(graph),
635 assembler_(codegen->GetAssembler()),
636 codegen_(codegen) {}
637
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000638void CodeGeneratorARM::ComputeSpillMask() {
639 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000640 // Save one extra register for baseline. Note that on thumb2, there is no easy
641 // instruction to restore just the PC, so this actually helps both baseline
642 // and non-baseline to save and restore at least two registers at entry and exit.
643 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000644 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
645 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
646 // We use vpush and vpop for saving and restoring floating point registers, which take
647 // a SRegister and the number of registers to save/restore after that SRegister. We
648 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
649 // but in the range.
650 if (fpu_spill_mask_ != 0) {
651 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
652 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
653 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
654 fpu_spill_mask_ |= (1 << i);
655 }
656 }
657}
658
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100659static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100660 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100661}
662
663static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100664 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100665}
666
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000667void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000668 bool skip_overflow_check =
669 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000670 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000671 __ Bind(&frame_entry_label_);
672
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000673 if (HasEmptyFrame()) {
674 return;
675 }
676
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100677 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000678 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
679 __ LoadFromOffset(kLoadWord, IP, IP, 0);
680 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100681 }
682
Andreas Gampe501fd632015-09-10 16:11:06 -0700683 __ PushList(core_spill_mask_);
684 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
685 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000686 if (fpu_spill_mask_ != 0) {
687 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
688 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100689 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100690 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000691 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100692 int adjust = GetFrameSize() - FrameEntrySpillSize();
693 __ AddConstant(SP, -adjust);
694 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100695 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000696}
697
698void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000699 if (HasEmptyFrame()) {
700 __ bx(LR);
701 return;
702 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100703 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100704 int adjust = GetFrameSize() - FrameEntrySpillSize();
705 __ AddConstant(SP, adjust);
706 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000707 if (fpu_spill_mask_ != 0) {
708 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
709 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100710 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
711 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000712 }
Andreas Gampe501fd632015-09-10 16:11:06 -0700713 // Pop LR into PC to return.
714 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
715 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
716 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +0100717 __ cfi().RestoreState();
718 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000719}
720
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100721void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700722 Label* label = GetLabelOf(block);
723 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000724}
725
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100726Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
727 switch (load->GetType()) {
728 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100729 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100730 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100731
732 case Primitive::kPrimInt:
733 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100734 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100735 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100736
737 case Primitive::kPrimBoolean:
738 case Primitive::kPrimByte:
739 case Primitive::kPrimChar:
740 case Primitive::kPrimShort:
741 case Primitive::kPrimVoid:
742 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700743 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100744 }
745
746 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700747 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100748}
749
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100750Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100751 switch (type) {
752 case Primitive::kPrimBoolean:
753 case Primitive::kPrimByte:
754 case Primitive::kPrimChar:
755 case Primitive::kPrimShort:
756 case Primitive::kPrimInt:
757 case Primitive::kPrimNot: {
758 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000759 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100760 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100761 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100762 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000763 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100764 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100765 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100766
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000767 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100768 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000769 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100770 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000771 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100772 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000773 if (calling_convention.GetRegisterAt(index) == R1) {
774 // Skip R1, and use R2_R3 instead.
775 gp_index_++;
776 index++;
777 }
778 }
779 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
780 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000781 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +0100782
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000783 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000784 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100785 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000786 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
787 }
788 }
789
790 case Primitive::kPrimFloat: {
791 uint32_t stack_index = stack_index_++;
792 if (float_index_ % 2 == 0) {
793 float_index_ = std::max(double_index_, float_index_);
794 }
795 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
796 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
797 } else {
798 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
799 }
800 }
801
802 case Primitive::kPrimDouble: {
803 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
804 uint32_t stack_index = stack_index_;
805 stack_index_ += 2;
806 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
807 uint32_t index = double_index_;
808 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000809 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000810 calling_convention.GetFpuRegisterAt(index),
811 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000812 DCHECK(ExpectedPairLayout(result));
813 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000814 } else {
815 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100816 }
817 }
818
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100819 case Primitive::kPrimVoid:
820 LOG(FATAL) << "Unexpected parameter type " << type;
821 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100822 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100823 return Location();
824}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100825
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100826Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000827 switch (type) {
828 case Primitive::kPrimBoolean:
829 case Primitive::kPrimByte:
830 case Primitive::kPrimChar:
831 case Primitive::kPrimShort:
832 case Primitive::kPrimInt:
833 case Primitive::kPrimNot: {
834 return Location::RegisterLocation(R0);
835 }
836
837 case Primitive::kPrimFloat: {
838 return Location::FpuRegisterLocation(S0);
839 }
840
841 case Primitive::kPrimLong: {
842 return Location::RegisterPairLocation(R0, R1);
843 }
844
845 case Primitive::kPrimDouble: {
846 return Location::FpuRegisterPairLocation(S0, S1);
847 }
848
849 case Primitive::kPrimVoid:
850 return Location();
851 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100852
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000853 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000854}
855
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100856Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
857 return Location::RegisterLocation(kMethodRegisterArgument);
858}
859
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100860void CodeGeneratorARM::Move32(Location destination, Location source) {
861 if (source.Equals(destination)) {
862 return;
863 }
864 if (destination.IsRegister()) {
865 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000866 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100867 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000868 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100869 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000870 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100871 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100872 } else if (destination.IsFpuRegister()) {
873 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000874 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100875 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000876 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100877 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000878 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100879 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100880 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000881 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100882 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000883 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100884 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000885 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100886 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000887 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100888 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
889 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100890 }
891 }
892}
893
894void CodeGeneratorARM::Move64(Location destination, Location source) {
895 if (source.Equals(destination)) {
896 return;
897 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100898 if (destination.IsRegisterPair()) {
899 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000900 EmitParallelMoves(
901 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
902 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100903 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000904 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100905 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
906 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100907 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000908 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +0100909 } else if (source.IsFpuRegisterPair()) {
910 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
911 destination.AsRegisterPairHigh<Register>(),
912 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100913 } else {
914 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000915 DCHECK(ExpectedPairLayout(destination));
916 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
917 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100918 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000919 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100920 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000921 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
922 SP,
923 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +0100924 } else if (source.IsRegisterPair()) {
925 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
926 source.AsRegisterPairLow<Register>(),
927 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100928 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000929 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100930 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100931 } else {
932 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100933 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000934 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100935 if (source.AsRegisterPairLow<Register>() == R1) {
936 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100937 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
938 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100939 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100940 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100941 SP, destination.GetStackIndex());
942 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000943 } else if (source.IsFpuRegisterPair()) {
944 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
945 SP,
946 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100947 } else {
948 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000949 EmitParallelMoves(
950 Location::StackSlot(source.GetStackIndex()),
951 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100952 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000953 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100954 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
955 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100956 }
957 }
958}
959
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100960void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100961 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100962 if (instruction->IsCurrentMethod()) {
963 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
964 } else if (locations != nullptr && locations->Out().Equals(location)) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100965 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100966 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000967 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000968 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
969 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +0000970 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000971 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000972 } else {
973 DCHECK(location.IsStackSlot());
974 __ LoadImmediate(IP, value);
975 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
976 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000977 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000978 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000979 int64_t value = const_to_move->AsLongConstant()->GetValue();
980 if (location.IsRegisterPair()) {
981 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
982 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
983 } else {
984 DCHECK(location.IsDoubleStackSlot());
985 __ LoadImmediate(IP, Low32Bits(value));
986 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
987 __ LoadImmediate(IP, High32Bits(value));
988 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
989 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100990 }
Roland Levillain476df552014-10-09 17:51:36 +0100991 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100992 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
993 switch (instruction->GetType()) {
994 case Primitive::kPrimBoolean:
995 case Primitive::kPrimByte:
996 case Primitive::kPrimChar:
997 case Primitive::kPrimShort:
998 case Primitive::kPrimInt:
999 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001000 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001001 Move32(location, Location::StackSlot(stack_slot));
1002 break;
1003
1004 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001005 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001006 Move64(location, Location::DoubleStackSlot(stack_slot));
1007 break;
1008
1009 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001010 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001011 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +00001012 } else if (instruction->IsTemporary()) {
1013 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +00001014 if (temp_location.IsStackSlot()) {
1015 Move32(location, temp_location);
1016 } else {
1017 DCHECK(temp_location.IsDoubleStackSlot());
1018 Move64(location, temp_location);
1019 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001020 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001021 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001022 switch (instruction->GetType()) {
1023 case Primitive::kPrimBoolean:
1024 case Primitive::kPrimByte:
1025 case Primitive::kPrimChar:
1026 case Primitive::kPrimShort:
1027 case Primitive::kPrimNot:
1028 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001029 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001030 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001031 break;
1032
1033 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001034 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001035 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001036 break;
1037
1038 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001039 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001040 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001041 }
1042}
1043
Calin Juravle175dc732015-08-25 15:42:32 +01001044void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
1045 DCHECK(location.IsRegister());
1046 __ LoadImmediate(location.AsRegister<Register>(), value);
1047}
1048
Calin Juravlee460d1d2015-09-29 04:52:17 +01001049void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
1050 if (Primitive::Is64BitType(dst_type)) {
1051 Move64(dst, src);
1052 } else {
1053 Move32(dst, src);
1054 }
1055}
1056
1057void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
1058 if (location.IsRegister()) {
1059 locations->AddTemp(location);
1060 } else if (location.IsRegisterPair()) {
1061 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1062 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
1063 } else {
1064 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1065 }
1066}
1067
Calin Juravle175dc732015-08-25 15:42:32 +01001068void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
1069 HInstruction* instruction,
1070 uint32_t dex_pc,
1071 SlowPathCode* slow_path) {
1072 InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(),
1073 instruction,
1074 dex_pc,
1075 slow_path);
1076}
1077
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001078void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
1079 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001080 uint32_t dex_pc,
1081 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +01001082 ValidateInvokeRuntime(instruction, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001083 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
1084 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001085 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001086}
1087
David Brazdilfc6a86a2015-06-26 10:33:45 +00001088void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001089 DCHECK(!successor->IsExitBlock());
1090
1091 HBasicBlock* block = got->GetBlock();
1092 HInstruction* previous = got->GetPrevious();
1093
1094 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001095 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001096 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1097 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1098 return;
1099 }
1100
1101 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1102 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1103 }
1104 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001105 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001106 }
1107}
1108
David Brazdilfc6a86a2015-06-26 10:33:45 +00001109void LocationsBuilderARM::VisitGoto(HGoto* got) {
1110 got->SetLocations(nullptr);
1111}
1112
1113void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
1114 HandleGoto(got, got->GetSuccessor());
1115}
1116
1117void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1118 try_boundary->SetLocations(nullptr);
1119}
1120
1121void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
1122 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1123 if (!successor->IsExitBlock()) {
1124 HandleGoto(try_boundary, successor);
1125 }
1126}
1127
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001128void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001129 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001130}
1131
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001132void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001133}
1134
Roland Levillain4fa13f62015-07-06 18:11:54 +01001135void InstructionCodeGeneratorARM::GenerateCompareWithImmediate(Register left, int32_t right) {
1136 ShifterOperand operand;
1137 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, right, &operand)) {
1138 __ cmp(left, operand);
1139 } else {
1140 Register temp = IP;
1141 __ LoadImmediate(temp, right);
1142 __ cmp(left, ShifterOperand(temp));
1143 }
1144}
1145
1146void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
1147 Label* true_label,
1148 Label* false_label) {
1149 __ vmstat(); // transfer FP status register to ARM APSR.
Aart Bike9f37602015-10-09 11:15:55 -07001150 // TODO: merge into a single branch (except "equal or unordered" and "not equal")
Roland Levillain4fa13f62015-07-06 18:11:54 +01001151 if (cond->IsFPConditionTrueIfNaN()) {
1152 __ b(true_label, VS); // VS for unordered.
1153 } else if (cond->IsFPConditionFalseIfNaN()) {
1154 __ b(false_label, VS); // VS for unordered.
1155 }
Aart Bike9f37602015-10-09 11:15:55 -07001156 __ b(true_label, ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001157}
1158
1159void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
1160 Label* true_label,
1161 Label* false_label) {
1162 LocationSummary* locations = cond->GetLocations();
1163 Location left = locations->InAt(0);
1164 Location right = locations->InAt(1);
1165 IfCondition if_cond = cond->GetCondition();
1166
1167 Register left_high = left.AsRegisterPairHigh<Register>();
1168 Register left_low = left.AsRegisterPairLow<Register>();
1169 IfCondition true_high_cond = if_cond;
1170 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001171 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01001172
1173 // Set the conditions for the test, remembering that == needs to be
1174 // decided using the low words.
Aart Bike9f37602015-10-09 11:15:55 -07001175 // TODO: consider avoiding jumps with temporary and CMP low+SBC high
Roland Levillain4fa13f62015-07-06 18:11:54 +01001176 switch (if_cond) {
1177 case kCondEQ:
1178 case kCondNE:
1179 // Nothing to do.
1180 break;
1181 case kCondLT:
1182 false_high_cond = kCondGT;
1183 break;
1184 case kCondLE:
1185 true_high_cond = kCondLT;
1186 break;
1187 case kCondGT:
1188 false_high_cond = kCondLT;
1189 break;
1190 case kCondGE:
1191 true_high_cond = kCondGT;
1192 break;
Aart Bike9f37602015-10-09 11:15:55 -07001193 case kCondB:
1194 false_high_cond = kCondA;
1195 break;
1196 case kCondBE:
1197 true_high_cond = kCondB;
1198 break;
1199 case kCondA:
1200 false_high_cond = kCondB;
1201 break;
1202 case kCondAE:
1203 true_high_cond = kCondA;
1204 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01001205 }
1206 if (right.IsConstant()) {
1207 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1208 int32_t val_low = Low32Bits(value);
1209 int32_t val_high = High32Bits(value);
1210
1211 GenerateCompareWithImmediate(left_high, val_high);
1212 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001213 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001214 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001215 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001216 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001217 __ b(true_label, ARMCondition(true_high_cond));
1218 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001219 }
1220 // Must be equal high, so compare the lows.
1221 GenerateCompareWithImmediate(left_low, val_low);
1222 } else {
1223 Register right_high = right.AsRegisterPairHigh<Register>();
1224 Register right_low = right.AsRegisterPairLow<Register>();
1225
1226 __ cmp(left_high, ShifterOperand(right_high));
1227 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001228 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001229 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001230 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001231 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001232 __ b(true_label, ARMCondition(true_high_cond));
1233 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001234 }
1235 // Must be equal high, so compare the lows.
1236 __ cmp(left_low, ShifterOperand(right_low));
1237 }
1238 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07001239 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01001240 __ b(true_label, final_condition);
1241}
1242
David Brazdil0debae72015-11-12 18:37:00 +00001243void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
1244 Label* true_target_in,
1245 Label* false_target_in) {
1246 // Generated branching requires both targets to be explicit. If either of the
1247 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
1248 Label fallthrough_target;
1249 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
1250 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
1251
Roland Levillain4fa13f62015-07-06 18:11:54 +01001252 LocationSummary* locations = condition->GetLocations();
1253 Location left = locations->InAt(0);
1254 Location right = locations->InAt(1);
1255
Roland Levillain4fa13f62015-07-06 18:11:54 +01001256 Primitive::Type type = condition->InputAt(0)->GetType();
1257 switch (type) {
1258 case Primitive::kPrimLong:
1259 GenerateLongComparesAndJumps(condition, true_target, false_target);
1260 break;
1261 case Primitive::kPrimFloat:
1262 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1263 GenerateFPJumps(condition, true_target, false_target);
1264 break;
1265 case Primitive::kPrimDouble:
1266 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1267 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1268 GenerateFPJumps(condition, true_target, false_target);
1269 break;
1270 default:
1271 LOG(FATAL) << "Unexpected compare type " << type;
1272 }
1273
David Brazdil0debae72015-11-12 18:37:00 +00001274 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001275 __ b(false_target);
1276 }
David Brazdil0debae72015-11-12 18:37:00 +00001277
1278 if (fallthrough_target.IsLinked()) {
1279 __ Bind(&fallthrough_target);
1280 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001281}
1282
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001283void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00001284 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001285 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00001286 Label* false_target) {
1287 HInstruction* cond = instruction->InputAt(condition_input_index);
1288
1289 if (true_target == nullptr && false_target == nullptr) {
1290 // Nothing to do. The code always falls through.
1291 return;
1292 } else if (cond->IsIntConstant()) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001293 // Constant condition, statically compared against 1.
David Brazdil0debae72015-11-12 18:37:00 +00001294 if (cond->AsIntConstant()->IsOne()) {
1295 if (true_target != nullptr) {
1296 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001297 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001298 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001299 DCHECK(cond->AsIntConstant()->IsZero());
1300 if (false_target != nullptr) {
1301 __ b(false_target);
1302 }
1303 }
1304 return;
1305 }
1306
1307 // The following code generates these patterns:
1308 // (1) true_target == nullptr && false_target != nullptr
1309 // - opposite condition true => branch to false_target
1310 // (2) true_target != nullptr && false_target == nullptr
1311 // - condition true => branch to true_target
1312 // (3) true_target != nullptr && false_target != nullptr
1313 // - condition true => branch to true_target
1314 // - branch to false_target
1315 if (IsBooleanValueOrMaterializedCondition(cond)) {
1316 // Condition has been materialized, compare the output to 0.
1317 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
1318 DCHECK(cond_val.IsRegister());
1319 if (true_target == nullptr) {
1320 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
1321 } else {
1322 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001323 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001324 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001325 // Condition has not been materialized. Use its inputs as the comparison and
1326 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04001327 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00001328
1329 // If this is a long or FP comparison that has been folded into
1330 // the HCondition, generate the comparison directly.
1331 Primitive::Type type = condition->InputAt(0)->GetType();
1332 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1333 GenerateCompareTestAndBranch(condition, true_target, false_target);
1334 return;
1335 }
1336
1337 LocationSummary* locations = cond->GetLocations();
1338 DCHECK(locations->InAt(0).IsRegister());
1339 Register left = locations->InAt(0).AsRegister<Register>();
1340 Location right = locations->InAt(1);
1341 if (right.IsRegister()) {
1342 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001343 } else {
David Brazdil0debae72015-11-12 18:37:00 +00001344 DCHECK(right.IsConstant());
1345 GenerateCompareWithImmediate(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1346 }
1347 if (true_target == nullptr) {
1348 __ b(false_target, ARMCondition(condition->GetOppositeCondition()));
1349 } else {
Mark Mendellb8b97692015-05-22 16:58:19 -04001350 __ b(true_target, ARMCondition(condition->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001351 }
Dave Allison20dfc792014-06-16 20:44:29 -07001352 }
David Brazdil0debae72015-11-12 18:37:00 +00001353
1354 // If neither branch falls through (case 3), the conditional branch to `true_target`
1355 // was already emitted (case 2) and we need to emit a jump to `false_target`.
1356 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001357 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001358 }
1359}
1360
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001361void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001362 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1363 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001364 locations->SetInAt(0, Location::RequiresRegister());
1365 }
1366}
1367
1368void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00001369 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
1370 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
1371 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
1372 nullptr : codegen_->GetLabelOf(true_successor);
1373 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
1374 nullptr : codegen_->GetLabelOf(false_successor);
1375 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001376}
1377
1378void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1379 LocationSummary* locations = new (GetGraph()->GetArena())
1380 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00001381 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001382 locations->SetInAt(0, Location::RequiresRegister());
1383 }
1384}
1385
1386void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
David Brazdil0debae72015-11-12 18:37:00 +00001387 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DeoptimizationSlowPathARM(deoptimize);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001388 codegen_->AddSlowPath(slow_path);
David Brazdil0debae72015-11-12 18:37:00 +00001389 GenerateTestAndBranch(deoptimize,
1390 /* condition_input_index */ 0,
1391 slow_path->GetEntryLabel(),
1392 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001393}
Dave Allison20dfc792014-06-16 20:44:29 -07001394
Roland Levillain0d37cd02015-05-27 16:39:19 +01001395void LocationsBuilderARM::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001396 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001397 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001398 // Handle the long/FP comparisons made in instruction simplification.
1399 switch (cond->InputAt(0)->GetType()) {
1400 case Primitive::kPrimLong:
1401 locations->SetInAt(0, Location::RequiresRegister());
1402 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1403 if (cond->NeedsMaterialization()) {
1404 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1405 }
1406 break;
1407
1408 case Primitive::kPrimFloat:
1409 case Primitive::kPrimDouble:
1410 locations->SetInAt(0, Location::RequiresFpuRegister());
1411 locations->SetInAt(1, Location::RequiresFpuRegister());
1412 if (cond->NeedsMaterialization()) {
1413 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1414 }
1415 break;
1416
1417 default:
1418 locations->SetInAt(0, Location::RequiresRegister());
1419 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1420 if (cond->NeedsMaterialization()) {
1421 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1422 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001423 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001424}
1425
Roland Levillain0d37cd02015-05-27 16:39:19 +01001426void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001427 if (!cond->NeedsMaterialization()) {
1428 return;
Dave Allison20dfc792014-06-16 20:44:29 -07001429 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001430
1431 LocationSummary* locations = cond->GetLocations();
1432 Location left = locations->InAt(0);
1433 Location right = locations->InAt(1);
1434 Register out = locations->Out().AsRegister<Register>();
1435 Label true_label, false_label;
1436
1437 switch (cond->InputAt(0)->GetType()) {
1438 default: {
1439 // Integer case.
1440 if (right.IsRegister()) {
1441 __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
1442 } else {
1443 DCHECK(right.IsConstant());
1444 GenerateCompareWithImmediate(left.AsRegister<Register>(),
1445 CodeGenerator::GetInt32ValueOf(right.GetConstant()));
1446 }
Aart Bike9f37602015-10-09 11:15:55 -07001447 __ it(ARMCondition(cond->GetCondition()), kItElse);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001448 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Aart Bike9f37602015-10-09 11:15:55 -07001449 ARMCondition(cond->GetCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001450 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Aart Bike9f37602015-10-09 11:15:55 -07001451 ARMCondition(cond->GetOppositeCondition()));
Roland Levillain4fa13f62015-07-06 18:11:54 +01001452 return;
1453 }
1454 case Primitive::kPrimLong:
1455 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1456 break;
1457 case Primitive::kPrimFloat:
1458 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
1459 GenerateFPJumps(cond, &true_label, &false_label);
1460 break;
1461 case Primitive::kPrimDouble:
1462 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
1463 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
1464 GenerateFPJumps(cond, &true_label, &false_label);
1465 break;
1466 }
1467
1468 // Convert the jumps into the result.
1469 Label done_label;
1470
1471 // False case: result = 0.
1472 __ Bind(&false_label);
1473 __ LoadImmediate(out, 0);
1474 __ b(&done_label);
1475
1476 // True case: result = 1.
1477 __ Bind(&true_label);
1478 __ LoadImmediate(out, 1);
1479 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001480}
1481
1482void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1483 VisitCondition(comp);
1484}
1485
1486void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1487 VisitCondition(comp);
1488}
1489
1490void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1491 VisitCondition(comp);
1492}
1493
1494void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1495 VisitCondition(comp);
1496}
1497
1498void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1499 VisitCondition(comp);
1500}
1501
1502void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1503 VisitCondition(comp);
1504}
1505
1506void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1507 VisitCondition(comp);
1508}
1509
1510void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1511 VisitCondition(comp);
1512}
1513
1514void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1515 VisitCondition(comp);
1516}
1517
1518void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1519 VisitCondition(comp);
1520}
1521
1522void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1523 VisitCondition(comp);
1524}
1525
1526void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1527 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001528}
1529
Aart Bike9f37602015-10-09 11:15:55 -07001530void LocationsBuilderARM::VisitBelow(HBelow* comp) {
1531 VisitCondition(comp);
1532}
1533
1534void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
1535 VisitCondition(comp);
1536}
1537
1538void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
1539 VisitCondition(comp);
1540}
1541
1542void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
1543 VisitCondition(comp);
1544}
1545
1546void LocationsBuilderARM::VisitAbove(HAbove* comp) {
1547 VisitCondition(comp);
1548}
1549
1550void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
1551 VisitCondition(comp);
1552}
1553
1554void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
1555 VisitCondition(comp);
1556}
1557
1558void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
1559 VisitCondition(comp);
1560}
1561
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001562void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001563 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001564}
1565
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001566void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1567 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001568}
1569
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001570void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001571 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001572}
1573
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001574void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001575 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001576}
1577
1578void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001579 LocationSummary* locations =
1580 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001581 switch (store->InputAt(1)->GetType()) {
1582 case Primitive::kPrimBoolean:
1583 case Primitive::kPrimByte:
1584 case Primitive::kPrimChar:
1585 case Primitive::kPrimShort:
1586 case Primitive::kPrimInt:
1587 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001588 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001589 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1590 break;
1591
1592 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001593 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001594 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1595 break;
1596
1597 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001598 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001599 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001600}
1601
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001602void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001603}
1604
1605void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001606 LocationSummary* locations =
1607 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001608 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001609}
1610
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001611void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001612 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001613}
1614
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001615void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1616 LocationSummary* locations =
1617 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1618 locations->SetOut(Location::ConstantLocation(constant));
1619}
1620
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001621void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001622 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001623}
1624
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001625void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001626 LocationSummary* locations =
1627 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001628 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001629}
1630
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001631void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001632 // Will be generated at use site.
1633}
1634
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001635void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1636 LocationSummary* locations =
1637 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1638 locations->SetOut(Location::ConstantLocation(constant));
1639}
1640
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001641void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001642 // Will be generated at use site.
1643}
1644
1645void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1646 LocationSummary* locations =
1647 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1648 locations->SetOut(Location::ConstantLocation(constant));
1649}
1650
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001651void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001652 // Will be generated at use site.
1653}
1654
Calin Juravle27df7582015-04-17 19:12:31 +01001655void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1656 memory_barrier->SetLocations(nullptr);
1657}
1658
1659void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1660 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1661}
1662
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001663void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001664 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001665}
1666
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001667void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001668 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001669}
1670
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001671void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001672 LocationSummary* locations =
1673 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001674 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001675}
1676
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001677void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001678 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001679}
1680
Calin Juravle175dc732015-08-25 15:42:32 +01001681void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1682 // The trampoline uses the same calling convention as dex calling conventions,
1683 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1684 // the method_idx.
1685 HandleInvoke(invoke);
1686}
1687
1688void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1689 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1690}
1691
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001692void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001693 // When we do not run baseline, explicit clinit checks triggered by static
1694 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1695 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001696
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001697 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001698 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001699 codegen_->GetInstructionSetFeatures());
1700 if (intrinsic.TryDispatch(invoke)) {
1701 return;
1702 }
1703
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001704 HandleInvoke(invoke);
1705}
1706
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001707static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1708 if (invoke->GetLocations()->Intrinsified()) {
1709 IntrinsicCodeGeneratorARM intrinsic(codegen);
1710 intrinsic.Dispatch(invoke);
1711 return true;
1712 }
1713 return false;
1714}
1715
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001716void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001717 // When we do not run baseline, explicit clinit checks triggered by static
1718 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1719 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001720
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001721 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1722 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001723 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001724
Nicolas Geoffray38207af2015-06-01 15:46:22 +01001725 LocationSummary* locations = invoke->GetLocations();
1726 codegen_->GenerateStaticOrDirectCall(
1727 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001728 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001729}
1730
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001731void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001732 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001733 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001734}
1735
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001736void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001737 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +01001738 codegen_->GetAssembler(),
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001739 codegen_->GetInstructionSetFeatures());
1740 if (intrinsic.TryDispatch(invoke)) {
1741 return;
1742 }
1743
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001744 HandleInvoke(invoke);
1745}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001746
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001747void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001748 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1749 return;
1750 }
1751
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001752 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001753 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001754 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001755}
1756
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001757void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1758 HandleInvoke(invoke);
1759 // Add the hidden argument.
1760 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1761}
1762
1763void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1764 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001765 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001766 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1767 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001768 LocationSummary* locations = invoke->GetLocations();
1769 Location receiver = locations->InAt(0);
1770 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1771
1772 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001773 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1774 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001775
1776 // temp = object->GetClass();
1777 if (receiver.IsStackSlot()) {
1778 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1779 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1780 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001781 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001782 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001783 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain4d027112015-07-01 15:41:14 +01001784 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001785 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001786 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001787 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001788 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1789 // LR = temp->GetEntryPoint();
1790 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1791 // LR();
1792 __ blx(LR);
1793 DCHECK(!codegen_->IsLeafMethod());
1794 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1795}
1796
Roland Levillain88cb1752014-10-20 16:36:47 +01001797void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1798 LocationSummary* locations =
1799 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1800 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001801 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001802 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001803 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1804 break;
1805 }
1806 case Primitive::kPrimLong: {
1807 locations->SetInAt(0, Location::RequiresRegister());
1808 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001809 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001810 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001811
Roland Levillain88cb1752014-10-20 16:36:47 +01001812 case Primitive::kPrimFloat:
1813 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001814 locations->SetInAt(0, Location::RequiresFpuRegister());
1815 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001816 break;
1817
1818 default:
1819 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1820 }
1821}
1822
1823void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1824 LocationSummary* locations = neg->GetLocations();
1825 Location out = locations->Out();
1826 Location in = locations->InAt(0);
1827 switch (neg->GetResultType()) {
1828 case Primitive::kPrimInt:
1829 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001830 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001831 break;
1832
1833 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001834 DCHECK(in.IsRegisterPair());
1835 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1836 __ rsbs(out.AsRegisterPairLow<Register>(),
1837 in.AsRegisterPairLow<Register>(),
1838 ShifterOperand(0));
1839 // We cannot emit an RSC (Reverse Subtract with Carry)
1840 // instruction here, as it does not exist in the Thumb-2
1841 // instruction set. We use the following approach
1842 // using SBC and SUB instead.
1843 //
1844 // out.hi = -C
1845 __ sbc(out.AsRegisterPairHigh<Register>(),
1846 out.AsRegisterPairHigh<Register>(),
1847 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1848 // out.hi = out.hi - in.hi
1849 __ sub(out.AsRegisterPairHigh<Register>(),
1850 out.AsRegisterPairHigh<Register>(),
1851 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1852 break;
1853
Roland Levillain88cb1752014-10-20 16:36:47 +01001854 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001855 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001856 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001857 break;
1858
Roland Levillain88cb1752014-10-20 16:36:47 +01001859 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001860 DCHECK(in.IsFpuRegisterPair());
1861 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1862 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001863 break;
1864
1865 default:
1866 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1867 }
1868}
1869
Roland Levillaindff1f282014-11-05 14:15:05 +00001870void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001871 Primitive::Type result_type = conversion->GetResultType();
1872 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001873 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001874
Roland Levillain5b3ee562015-04-14 16:02:41 +01001875 // The float-to-long, double-to-long and long-to-float type conversions
1876 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001877 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01001878 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1879 && result_type == Primitive::kPrimLong)
1880 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00001881 ? LocationSummary::kCall
1882 : LocationSummary::kNoCall;
1883 LocationSummary* locations =
1884 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1885
David Brazdilb2bd1c52015-03-25 11:17:37 +00001886 // The Java language does not allow treating boolean as an integral type but
1887 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001888
Roland Levillaindff1f282014-11-05 14:15:05 +00001889 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001890 case Primitive::kPrimByte:
1891 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001892 case Primitive::kPrimBoolean:
1893 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001894 case Primitive::kPrimShort:
1895 case Primitive::kPrimInt:
1896 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001897 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001898 locations->SetInAt(0, Location::RequiresRegister());
1899 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1900 break;
1901
1902 default:
1903 LOG(FATAL) << "Unexpected type conversion from " << input_type
1904 << " to " << result_type;
1905 }
1906 break;
1907
Roland Levillain01a8d712014-11-14 16:27:39 +00001908 case Primitive::kPrimShort:
1909 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001910 case Primitive::kPrimBoolean:
1911 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001912 case Primitive::kPrimByte:
1913 case Primitive::kPrimInt:
1914 case Primitive::kPrimChar:
1915 // Processing a Dex `int-to-short' instruction.
1916 locations->SetInAt(0, Location::RequiresRegister());
1917 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1918 break;
1919
1920 default:
1921 LOG(FATAL) << "Unexpected type conversion from " << input_type
1922 << " to " << result_type;
1923 }
1924 break;
1925
Roland Levillain946e1432014-11-11 17:35:19 +00001926 case Primitive::kPrimInt:
1927 switch (input_type) {
1928 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001929 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001930 locations->SetInAt(0, Location::Any());
1931 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1932 break;
1933
1934 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001935 // Processing a Dex `float-to-int' instruction.
1936 locations->SetInAt(0, Location::RequiresFpuRegister());
1937 locations->SetOut(Location::RequiresRegister());
1938 locations->AddTemp(Location::RequiresFpuRegister());
1939 break;
1940
Roland Levillain946e1432014-11-11 17:35:19 +00001941 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001942 // Processing a Dex `double-to-int' instruction.
1943 locations->SetInAt(0, Location::RequiresFpuRegister());
1944 locations->SetOut(Location::RequiresRegister());
1945 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001946 break;
1947
1948 default:
1949 LOG(FATAL) << "Unexpected type conversion from " << input_type
1950 << " to " << result_type;
1951 }
1952 break;
1953
Roland Levillaindff1f282014-11-05 14:15:05 +00001954 case Primitive::kPrimLong:
1955 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001956 case Primitive::kPrimBoolean:
1957 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001958 case Primitive::kPrimByte:
1959 case Primitive::kPrimShort:
1960 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001961 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001962 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001963 locations->SetInAt(0, Location::RequiresRegister());
1964 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1965 break;
1966
Roland Levillain624279f2014-12-04 11:54:28 +00001967 case Primitive::kPrimFloat: {
1968 // Processing a Dex `float-to-long' instruction.
1969 InvokeRuntimeCallingConvention calling_convention;
1970 locations->SetInAt(0, Location::FpuRegisterLocation(
1971 calling_convention.GetFpuRegisterAt(0)));
1972 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1973 break;
1974 }
1975
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001976 case Primitive::kPrimDouble: {
1977 // Processing a Dex `double-to-long' instruction.
1978 InvokeRuntimeCallingConvention calling_convention;
1979 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1980 calling_convention.GetFpuRegisterAt(0),
1981 calling_convention.GetFpuRegisterAt(1)));
1982 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001983 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001984 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001985
1986 default:
1987 LOG(FATAL) << "Unexpected type conversion from " << input_type
1988 << " to " << result_type;
1989 }
1990 break;
1991
Roland Levillain981e4542014-11-14 11:47:14 +00001992 case Primitive::kPrimChar:
1993 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001994 case Primitive::kPrimBoolean:
1995 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001996 case Primitive::kPrimByte:
1997 case Primitive::kPrimShort:
1998 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001999 // Processing a Dex `int-to-char' instruction.
2000 locations->SetInAt(0, Location::RequiresRegister());
2001 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2002 break;
2003
2004 default:
2005 LOG(FATAL) << "Unexpected type conversion from " << input_type
2006 << " to " << result_type;
2007 }
2008 break;
2009
Roland Levillaindff1f282014-11-05 14:15:05 +00002010 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002011 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002012 case Primitive::kPrimBoolean:
2013 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002014 case Primitive::kPrimByte:
2015 case Primitive::kPrimShort:
2016 case Primitive::kPrimInt:
2017 case Primitive::kPrimChar:
2018 // Processing a Dex `int-to-float' instruction.
2019 locations->SetInAt(0, Location::RequiresRegister());
2020 locations->SetOut(Location::RequiresFpuRegister());
2021 break;
2022
Roland Levillain5b3ee562015-04-14 16:02:41 +01002023 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00002024 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002025 InvokeRuntimeCallingConvention calling_convention;
2026 locations->SetInAt(0, Location::RegisterPairLocation(
2027 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2028 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00002029 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01002030 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002031
Roland Levillaincff13742014-11-17 14:32:17 +00002032 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002033 // Processing a Dex `double-to-float' instruction.
2034 locations->SetInAt(0, Location::RequiresFpuRegister());
2035 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002036 break;
2037
2038 default:
2039 LOG(FATAL) << "Unexpected type conversion from " << input_type
2040 << " to " << result_type;
2041 };
2042 break;
2043
Roland Levillaindff1f282014-11-05 14:15:05 +00002044 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002045 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002046 case Primitive::kPrimBoolean:
2047 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002048 case Primitive::kPrimByte:
2049 case Primitive::kPrimShort:
2050 case Primitive::kPrimInt:
2051 case Primitive::kPrimChar:
2052 // Processing a Dex `int-to-double' instruction.
2053 locations->SetInAt(0, Location::RequiresRegister());
2054 locations->SetOut(Location::RequiresFpuRegister());
2055 break;
2056
2057 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002058 // Processing a Dex `long-to-double' instruction.
2059 locations->SetInAt(0, Location::RequiresRegister());
2060 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01002061 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002062 locations->AddTemp(Location::RequiresFpuRegister());
2063 break;
2064
Roland Levillaincff13742014-11-17 14:32:17 +00002065 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002066 // Processing a Dex `float-to-double' instruction.
2067 locations->SetInAt(0, Location::RequiresFpuRegister());
2068 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002069 break;
2070
2071 default:
2072 LOG(FATAL) << "Unexpected type conversion from " << input_type
2073 << " to " << result_type;
2074 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002075 break;
2076
2077 default:
2078 LOG(FATAL) << "Unexpected type conversion from " << input_type
2079 << " to " << result_type;
2080 }
2081}
2082
2083void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
2084 LocationSummary* locations = conversion->GetLocations();
2085 Location out = locations->Out();
2086 Location in = locations->InAt(0);
2087 Primitive::Type result_type = conversion->GetResultType();
2088 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002089 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002090 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002091 case Primitive::kPrimByte:
2092 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002093 case Primitive::kPrimBoolean:
2094 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002095 case Primitive::kPrimShort:
2096 case Primitive::kPrimInt:
2097 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002098 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002099 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00002100 break;
2101
2102 default:
2103 LOG(FATAL) << "Unexpected type conversion from " << input_type
2104 << " to " << result_type;
2105 }
2106 break;
2107
Roland Levillain01a8d712014-11-14 16:27:39 +00002108 case Primitive::kPrimShort:
2109 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002110 case Primitive::kPrimBoolean:
2111 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002112 case Primitive::kPrimByte:
2113 case Primitive::kPrimInt:
2114 case Primitive::kPrimChar:
2115 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002116 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00002117 break;
2118
2119 default:
2120 LOG(FATAL) << "Unexpected type conversion from " << input_type
2121 << " to " << result_type;
2122 }
2123 break;
2124
Roland Levillain946e1432014-11-11 17:35:19 +00002125 case Primitive::kPrimInt:
2126 switch (input_type) {
2127 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002128 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002129 DCHECK(out.IsRegister());
2130 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002131 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002132 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002133 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00002134 } else {
2135 DCHECK(in.IsConstant());
2136 DCHECK(in.GetConstant()->IsLongConstant());
2137 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002138 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00002139 }
2140 break;
2141
Roland Levillain3f8f9362014-12-02 17:45:01 +00002142 case Primitive::kPrimFloat: {
2143 // Processing a Dex `float-to-int' instruction.
2144 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2145 __ vmovs(temp, in.AsFpuRegister<SRegister>());
2146 __ vcvtis(temp, temp);
2147 __ vmovrs(out.AsRegister<Register>(), temp);
2148 break;
2149 }
2150
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002151 case Primitive::kPrimDouble: {
2152 // Processing a Dex `double-to-int' instruction.
2153 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
2154 DRegister temp_d = FromLowSToD(temp_s);
2155 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2156 __ vcvtid(temp_s, temp_d);
2157 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00002158 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002159 }
Roland Levillain946e1432014-11-11 17:35:19 +00002160
2161 default:
2162 LOG(FATAL) << "Unexpected type conversion from " << input_type
2163 << " to " << result_type;
2164 }
2165 break;
2166
Roland Levillaindff1f282014-11-05 14:15:05 +00002167 case Primitive::kPrimLong:
2168 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002169 case Primitive::kPrimBoolean:
2170 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002171 case Primitive::kPrimByte:
2172 case Primitive::kPrimShort:
2173 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002174 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002175 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002176 DCHECK(out.IsRegisterPair());
2177 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002178 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00002179 // Sign extension.
2180 __ Asr(out.AsRegisterPairHigh<Register>(),
2181 out.AsRegisterPairLow<Register>(),
2182 31);
2183 break;
2184
2185 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002186 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00002187 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2188 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002189 conversion->GetDexPc(),
2190 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002191 break;
2192
Roland Levillaindff1f282014-11-05 14:15:05 +00002193 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002194 // Processing a Dex `double-to-long' instruction.
2195 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2196 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002197 conversion->GetDexPc(),
2198 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002199 break;
2200
2201 default:
2202 LOG(FATAL) << "Unexpected type conversion from " << input_type
2203 << " to " << result_type;
2204 }
2205 break;
2206
Roland Levillain981e4542014-11-14 11:47:14 +00002207 case Primitive::kPrimChar:
2208 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002209 case Primitive::kPrimBoolean:
2210 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002211 case Primitive::kPrimByte:
2212 case Primitive::kPrimShort:
2213 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002214 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002215 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00002216 break;
2217
2218 default:
2219 LOG(FATAL) << "Unexpected type conversion from " << input_type
2220 << " to " << result_type;
2221 }
2222 break;
2223
Roland Levillaindff1f282014-11-05 14:15:05 +00002224 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002225 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002226 case Primitive::kPrimBoolean:
2227 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002228 case Primitive::kPrimByte:
2229 case Primitive::kPrimShort:
2230 case Primitive::kPrimInt:
2231 case Primitive::kPrimChar: {
2232 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002233 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
2234 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002235 break;
2236 }
2237
Roland Levillain5b3ee562015-04-14 16:02:41 +01002238 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002239 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01002240 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
2241 conversion,
2242 conversion->GetDexPc(),
2243 nullptr);
Roland Levillain6d0e4832014-11-27 18:31:21 +00002244 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002245
Roland Levillaincff13742014-11-17 14:32:17 +00002246 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002247 // Processing a Dex `double-to-float' instruction.
2248 __ vcvtsd(out.AsFpuRegister<SRegister>(),
2249 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00002250 break;
2251
2252 default:
2253 LOG(FATAL) << "Unexpected type conversion from " << input_type
2254 << " to " << result_type;
2255 };
2256 break;
2257
Roland Levillaindff1f282014-11-05 14:15:05 +00002258 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002259 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002260 case Primitive::kPrimBoolean:
2261 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002262 case Primitive::kPrimByte:
2263 case Primitive::kPrimShort:
2264 case Primitive::kPrimInt:
2265 case Primitive::kPrimChar: {
2266 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002267 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002268 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2269 out.AsFpuRegisterPairLow<SRegister>());
2270 break;
2271 }
2272
Roland Levillain647b9ed2014-11-27 12:06:00 +00002273 case Primitive::kPrimLong: {
2274 // Processing a Dex `long-to-double' instruction.
2275 Register low = in.AsRegisterPairLow<Register>();
2276 Register high = in.AsRegisterPairHigh<Register>();
2277 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
2278 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002279 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00002280 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01002281 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
2282 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002283
Roland Levillain682393c2015-04-14 15:57:52 +01002284 // temp_d = int-to-double(high)
2285 __ vmovsr(temp_s, high);
2286 __ vcvtdi(temp_d, temp_s);
2287 // constant_d = k2Pow32EncodingForDouble
2288 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
2289 // out_d = unsigned-to-double(low)
2290 __ vmovsr(out_s, low);
2291 __ vcvtdu(out_d, out_s);
2292 // out_d += temp_d * constant_d
2293 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00002294 break;
2295 }
2296
Roland Levillaincff13742014-11-17 14:32:17 +00002297 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002298 // Processing a Dex `float-to-double' instruction.
2299 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2300 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002301 break;
2302
2303 default:
2304 LOG(FATAL) << "Unexpected type conversion from " << input_type
2305 << " to " << result_type;
2306 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002307 break;
2308
2309 default:
2310 LOG(FATAL) << "Unexpected type conversion from " << input_type
2311 << " to " << result_type;
2312 }
2313}
2314
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002315void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002316 LocationSummary* locations =
2317 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002318 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002319 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002320 locations->SetInAt(0, Location::RequiresRegister());
2321 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002322 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2323 break;
2324 }
2325
2326 case Primitive::kPrimLong: {
2327 locations->SetInAt(0, Location::RequiresRegister());
2328 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002329 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002330 break;
2331 }
2332
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002333 case Primitive::kPrimFloat:
2334 case Primitive::kPrimDouble: {
2335 locations->SetInAt(0, Location::RequiresFpuRegister());
2336 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002337 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002338 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002339 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002340
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002341 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002342 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002343 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002344}
2345
2346void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
2347 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002348 Location out = locations->Out();
2349 Location first = locations->InAt(0);
2350 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002351 switch (add->GetResultType()) {
2352 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002353 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002354 __ add(out.AsRegister<Register>(),
2355 first.AsRegister<Register>(),
2356 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002357 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002358 __ AddConstant(out.AsRegister<Register>(),
2359 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002360 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002361 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002362 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002363
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002364 case Primitive::kPrimLong: {
2365 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002366 __ adds(out.AsRegisterPairLow<Register>(),
2367 first.AsRegisterPairLow<Register>(),
2368 ShifterOperand(second.AsRegisterPairLow<Register>()));
2369 __ adc(out.AsRegisterPairHigh<Register>(),
2370 first.AsRegisterPairHigh<Register>(),
2371 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002372 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002373 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002374
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002375 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00002376 __ vadds(out.AsFpuRegister<SRegister>(),
2377 first.AsFpuRegister<SRegister>(),
2378 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002379 break;
2380
2381 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002382 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2383 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2384 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002385 break;
2386
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002387 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002388 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002389 }
2390}
2391
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002392void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002393 LocationSummary* locations =
2394 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002395 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002396 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002397 locations->SetInAt(0, Location::RequiresRegister());
2398 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002399 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2400 break;
2401 }
2402
2403 case Primitive::kPrimLong: {
2404 locations->SetInAt(0, Location::RequiresRegister());
2405 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002406 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002407 break;
2408 }
Calin Juravle11351682014-10-23 15:38:15 +01002409 case Primitive::kPrimFloat:
2410 case Primitive::kPrimDouble: {
2411 locations->SetInAt(0, Location::RequiresFpuRegister());
2412 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002413 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002414 break;
Calin Juravle11351682014-10-23 15:38:15 +01002415 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002416 default:
Calin Juravle11351682014-10-23 15:38:15 +01002417 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002418 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002419}
2420
2421void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2422 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002423 Location out = locations->Out();
2424 Location first = locations->InAt(0);
2425 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002426 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002427 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002428 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002429 __ sub(out.AsRegister<Register>(),
2430 first.AsRegister<Register>(),
2431 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002432 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002433 __ AddConstant(out.AsRegister<Register>(),
2434 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002435 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002436 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002437 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002438 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002439
Calin Juravle11351682014-10-23 15:38:15 +01002440 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002441 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002442 __ subs(out.AsRegisterPairLow<Register>(),
2443 first.AsRegisterPairLow<Register>(),
2444 ShifterOperand(second.AsRegisterPairLow<Register>()));
2445 __ sbc(out.AsRegisterPairHigh<Register>(),
2446 first.AsRegisterPairHigh<Register>(),
2447 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002448 break;
Calin Juravle11351682014-10-23 15:38:15 +01002449 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002450
Calin Juravle11351682014-10-23 15:38:15 +01002451 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002452 __ vsubs(out.AsFpuRegister<SRegister>(),
2453 first.AsFpuRegister<SRegister>(),
2454 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002455 break;
Calin Juravle11351682014-10-23 15:38:15 +01002456 }
2457
2458 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002459 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2460 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2461 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002462 break;
2463 }
2464
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002465
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002466 default:
Calin Juravle11351682014-10-23 15:38:15 +01002467 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002468 }
2469}
2470
Calin Juravle34bacdf2014-10-07 20:23:36 +01002471void LocationsBuilderARM::VisitMul(HMul* mul) {
2472 LocationSummary* locations =
2473 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2474 switch (mul->GetResultType()) {
2475 case Primitive::kPrimInt:
2476 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002477 locations->SetInAt(0, Location::RequiresRegister());
2478 locations->SetInAt(1, Location::RequiresRegister());
2479 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002480 break;
2481 }
2482
Calin Juravleb5bfa962014-10-21 18:02:24 +01002483 case Primitive::kPrimFloat:
2484 case Primitive::kPrimDouble: {
2485 locations->SetInAt(0, Location::RequiresFpuRegister());
2486 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002487 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002488 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002489 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002490
2491 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002492 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002493 }
2494}
2495
2496void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2497 LocationSummary* locations = mul->GetLocations();
2498 Location out = locations->Out();
2499 Location first = locations->InAt(0);
2500 Location second = locations->InAt(1);
2501 switch (mul->GetResultType()) {
2502 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002503 __ mul(out.AsRegister<Register>(),
2504 first.AsRegister<Register>(),
2505 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002506 break;
2507 }
2508 case Primitive::kPrimLong: {
2509 Register out_hi = out.AsRegisterPairHigh<Register>();
2510 Register out_lo = out.AsRegisterPairLow<Register>();
2511 Register in1_hi = first.AsRegisterPairHigh<Register>();
2512 Register in1_lo = first.AsRegisterPairLow<Register>();
2513 Register in2_hi = second.AsRegisterPairHigh<Register>();
2514 Register in2_lo = second.AsRegisterPairLow<Register>();
2515
2516 // Extra checks to protect caused by the existence of R1_R2.
2517 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2518 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2519 DCHECK_NE(out_hi, in1_lo);
2520 DCHECK_NE(out_hi, in2_lo);
2521
2522 // input: in1 - 64 bits, in2 - 64 bits
2523 // output: out
2524 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2525 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2526 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2527
2528 // IP <- in1.lo * in2.hi
2529 __ mul(IP, in1_lo, in2_hi);
2530 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2531 __ mla(out_hi, in1_hi, in2_lo, IP);
2532 // out.lo <- (in1.lo * in2.lo)[31:0];
2533 __ umull(out_lo, IP, in1_lo, in2_lo);
2534 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2535 __ add(out_hi, out_hi, ShifterOperand(IP));
2536 break;
2537 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002538
2539 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002540 __ vmuls(out.AsFpuRegister<SRegister>(),
2541 first.AsFpuRegister<SRegister>(),
2542 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002543 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002544 }
2545
2546 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002547 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2548 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2549 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002550 break;
2551 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002552
2553 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002554 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002555 }
2556}
2557
Zheng Xuc6667102015-05-15 16:08:45 +08002558void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2559 DCHECK(instruction->IsDiv() || instruction->IsRem());
2560 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2561
2562 LocationSummary* locations = instruction->GetLocations();
2563 Location second = locations->InAt(1);
2564 DCHECK(second.IsConstant());
2565
2566 Register out = locations->Out().AsRegister<Register>();
2567 Register dividend = locations->InAt(0).AsRegister<Register>();
2568 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2569 DCHECK(imm == 1 || imm == -1);
2570
2571 if (instruction->IsRem()) {
2572 __ LoadImmediate(out, 0);
2573 } else {
2574 if (imm == 1) {
2575 __ Mov(out, dividend);
2576 } else {
2577 __ rsb(out, dividend, ShifterOperand(0));
2578 }
2579 }
2580}
2581
2582void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2583 DCHECK(instruction->IsDiv() || instruction->IsRem());
2584 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2585
2586 LocationSummary* locations = instruction->GetLocations();
2587 Location second = locations->InAt(1);
2588 DCHECK(second.IsConstant());
2589
2590 Register out = locations->Out().AsRegister<Register>();
2591 Register dividend = locations->InAt(0).AsRegister<Register>();
2592 Register temp = locations->GetTemp(0).AsRegister<Register>();
2593 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Vladimir Marko80afd022015-05-19 18:08:00 +01002594 uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002595 DCHECK(IsPowerOfTwo(abs_imm));
2596 int ctz_imm = CTZ(abs_imm);
2597
2598 if (ctz_imm == 1) {
2599 __ Lsr(temp, dividend, 32 - ctz_imm);
2600 } else {
2601 __ Asr(temp, dividend, 31);
2602 __ Lsr(temp, temp, 32 - ctz_imm);
2603 }
2604 __ add(out, temp, ShifterOperand(dividend));
2605
2606 if (instruction->IsDiv()) {
2607 __ Asr(out, out, ctz_imm);
2608 if (imm < 0) {
2609 __ rsb(out, out, ShifterOperand(0));
2610 }
2611 } else {
2612 __ ubfx(out, out, 0, ctz_imm);
2613 __ sub(out, out, ShifterOperand(temp));
2614 }
2615}
2616
2617void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2618 DCHECK(instruction->IsDiv() || instruction->IsRem());
2619 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2620
2621 LocationSummary* locations = instruction->GetLocations();
2622 Location second = locations->InAt(1);
2623 DCHECK(second.IsConstant());
2624
2625 Register out = locations->Out().AsRegister<Register>();
2626 Register dividend = locations->InAt(0).AsRegister<Register>();
2627 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2628 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2629 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2630
2631 int64_t magic;
2632 int shift;
2633 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2634
2635 __ LoadImmediate(temp1, magic);
2636 __ smull(temp2, temp1, dividend, temp1);
2637
2638 if (imm > 0 && magic < 0) {
2639 __ add(temp1, temp1, ShifterOperand(dividend));
2640 } else if (imm < 0 && magic > 0) {
2641 __ sub(temp1, temp1, ShifterOperand(dividend));
2642 }
2643
2644 if (shift != 0) {
2645 __ Asr(temp1, temp1, shift);
2646 }
2647
2648 if (instruction->IsDiv()) {
2649 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2650 } else {
2651 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2652 // TODO: Strength reduction for mls.
2653 __ LoadImmediate(temp2, imm);
2654 __ mls(out, temp1, temp2, dividend);
2655 }
2656}
2657
2658void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2659 DCHECK(instruction->IsDiv() || instruction->IsRem());
2660 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2661
2662 LocationSummary* locations = instruction->GetLocations();
2663 Location second = locations->InAt(1);
2664 DCHECK(second.IsConstant());
2665
2666 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2667 if (imm == 0) {
2668 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2669 } else if (imm == 1 || imm == -1) {
2670 DivRemOneOrMinusOne(instruction);
2671 } else if (IsPowerOfTwo(std::abs(imm))) {
2672 DivRemByPowerOfTwo(instruction);
2673 } else {
2674 DCHECK(imm <= -2 || imm >= 2);
2675 GenerateDivRemWithAnyConstant(instruction);
2676 }
2677}
2678
Calin Juravle7c4954d2014-10-28 16:57:40 +00002679void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002680 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2681 if (div->GetResultType() == Primitive::kPrimLong) {
2682 // pLdiv runtime call.
2683 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002684 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2685 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002686 } else if (div->GetResultType() == Primitive::kPrimInt &&
2687 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2688 // pIdivmod runtime call.
2689 call_kind = LocationSummary::kCall;
2690 }
2691
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002692 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2693
Calin Juravle7c4954d2014-10-28 16:57:40 +00002694 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002695 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002696 if (div->InputAt(1)->IsConstant()) {
2697 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002698 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002699 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2700 int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2701 if (abs_imm <= 1) {
2702 // No temp register required.
2703 } else {
2704 locations->AddTemp(Location::RequiresRegister());
2705 if (!IsPowerOfTwo(abs_imm)) {
2706 locations->AddTemp(Location::RequiresRegister());
2707 }
2708 }
2709 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002710 locations->SetInAt(0, Location::RequiresRegister());
2711 locations->SetInAt(1, Location::RequiresRegister());
2712 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2713 } else {
2714 InvokeRuntimeCallingConvention calling_convention;
2715 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2716 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2717 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2718 // we only need the former.
2719 locations->SetOut(Location::RegisterLocation(R0));
2720 }
Calin Juravled0d48522014-11-04 16:40:20 +00002721 break;
2722 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002723 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002724 InvokeRuntimeCallingConvention calling_convention;
2725 locations->SetInAt(0, Location::RegisterPairLocation(
2726 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2727 locations->SetInAt(1, Location::RegisterPairLocation(
2728 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002729 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002730 break;
2731 }
2732 case Primitive::kPrimFloat:
2733 case Primitive::kPrimDouble: {
2734 locations->SetInAt(0, Location::RequiresFpuRegister());
2735 locations->SetInAt(1, Location::RequiresFpuRegister());
2736 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2737 break;
2738 }
2739
2740 default:
2741 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2742 }
2743}
2744
2745void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2746 LocationSummary* locations = div->GetLocations();
2747 Location out = locations->Out();
2748 Location first = locations->InAt(0);
2749 Location second = locations->InAt(1);
2750
2751 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002752 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002753 if (second.IsConstant()) {
2754 GenerateDivRemConstantIntegral(div);
2755 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002756 __ sdiv(out.AsRegister<Register>(),
2757 first.AsRegister<Register>(),
2758 second.AsRegister<Register>());
2759 } else {
2760 InvokeRuntimeCallingConvention calling_convention;
2761 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2762 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2763 DCHECK_EQ(R0, out.AsRegister<Register>());
2764
2765 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2766 }
Calin Juravled0d48522014-11-04 16:40:20 +00002767 break;
2768 }
2769
Calin Juravle7c4954d2014-10-28 16:57:40 +00002770 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002771 InvokeRuntimeCallingConvention calling_convention;
2772 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2773 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2774 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2775 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2776 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002777 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002778
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002779 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002780 break;
2781 }
2782
2783 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002784 __ vdivs(out.AsFpuRegister<SRegister>(),
2785 first.AsFpuRegister<SRegister>(),
2786 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002787 break;
2788 }
2789
2790 case Primitive::kPrimDouble: {
2791 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2792 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2793 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2794 break;
2795 }
2796
2797 default:
2798 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2799 }
2800}
2801
Calin Juravlebacfec32014-11-14 15:54:36 +00002802void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002803 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002804
2805 // Most remainders are implemented in the runtime.
2806 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002807 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
2808 // sdiv will be replaced by other instruction sequence.
2809 call_kind = LocationSummary::kNoCall;
2810 } else if ((rem->GetResultType() == Primitive::kPrimInt)
2811 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002812 // Have hardware divide instruction for int, do it with three instructions.
2813 call_kind = LocationSummary::kNoCall;
2814 }
2815
Calin Juravlebacfec32014-11-14 15:54:36 +00002816 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2817
Calin Juravled2ec87d2014-12-08 14:24:46 +00002818 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002819 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002820 if (rem->InputAt(1)->IsConstant()) {
2821 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00002822 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08002823 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2824 int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
2825 if (abs_imm <= 1) {
2826 // No temp register required.
2827 } else {
2828 locations->AddTemp(Location::RequiresRegister());
2829 if (!IsPowerOfTwo(abs_imm)) {
2830 locations->AddTemp(Location::RequiresRegister());
2831 }
2832 }
2833 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002834 locations->SetInAt(0, Location::RequiresRegister());
2835 locations->SetInAt(1, Location::RequiresRegister());
2836 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2837 locations->AddTemp(Location::RequiresRegister());
2838 } else {
2839 InvokeRuntimeCallingConvention calling_convention;
2840 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2841 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2842 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2843 // we only need the latter.
2844 locations->SetOut(Location::RegisterLocation(R1));
2845 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002846 break;
2847 }
2848 case Primitive::kPrimLong: {
2849 InvokeRuntimeCallingConvention calling_convention;
2850 locations->SetInAt(0, Location::RegisterPairLocation(
2851 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2852 locations->SetInAt(1, Location::RegisterPairLocation(
2853 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2854 // The runtime helper puts the output in R2,R3.
2855 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2856 break;
2857 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002858 case Primitive::kPrimFloat: {
2859 InvokeRuntimeCallingConvention calling_convention;
2860 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2861 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2862 locations->SetOut(Location::FpuRegisterLocation(S0));
2863 break;
2864 }
2865
Calin Juravlebacfec32014-11-14 15:54:36 +00002866 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002867 InvokeRuntimeCallingConvention calling_convention;
2868 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2869 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2870 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2871 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2872 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002873 break;
2874 }
2875
2876 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002877 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002878 }
2879}
2880
2881void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2882 LocationSummary* locations = rem->GetLocations();
2883 Location out = locations->Out();
2884 Location first = locations->InAt(0);
2885 Location second = locations->InAt(1);
2886
Calin Juravled2ec87d2014-12-08 14:24:46 +00002887 Primitive::Type type = rem->GetResultType();
2888 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002889 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002890 if (second.IsConstant()) {
2891 GenerateDivRemConstantIntegral(rem);
2892 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002893 Register reg1 = first.AsRegister<Register>();
2894 Register reg2 = second.AsRegister<Register>();
2895 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002896
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002897 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002898 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002899 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01002900 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002901 } else {
2902 InvokeRuntimeCallingConvention calling_convention;
2903 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2904 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2905 DCHECK_EQ(R1, out.AsRegister<Register>());
2906
2907 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2908 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002909 break;
2910 }
2911
2912 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002913 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002914 break;
2915 }
2916
Calin Juravled2ec87d2014-12-08 14:24:46 +00002917 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002918 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002919 break;
2920 }
2921
Calin Juravlebacfec32014-11-14 15:54:36 +00002922 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002923 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002924 break;
2925 }
2926
2927 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002928 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002929 }
2930}
2931
Calin Juravled0d48522014-11-04 16:40:20 +00002932void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00002933 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
2934 ? LocationSummary::kCallOnSlowPath
2935 : LocationSummary::kNoCall;
2936 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002937 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002938 if (instruction->HasUses()) {
2939 locations->SetOut(Location::SameAsFirstInput());
2940 }
2941}
2942
2943void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07002944 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00002945 codegen_->AddSlowPath(slow_path);
2946
2947 LocationSummary* locations = instruction->GetLocations();
2948 Location value = locations->InAt(0);
2949
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002950 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06002951 case Primitive::kPrimByte:
2952 case Primitive::kPrimChar:
2953 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002954 case Primitive::kPrimInt: {
2955 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01002956 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002957 } else {
2958 DCHECK(value.IsConstant()) << value;
2959 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2960 __ b(slow_path->GetEntryLabel());
2961 }
2962 }
2963 break;
2964 }
2965 case Primitive::kPrimLong: {
2966 if (value.IsRegisterPair()) {
2967 __ orrs(IP,
2968 value.AsRegisterPairLow<Register>(),
2969 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2970 __ b(slow_path->GetEntryLabel(), EQ);
2971 } else {
2972 DCHECK(value.IsConstant()) << value;
2973 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2974 __ b(slow_path->GetEntryLabel());
2975 }
2976 }
2977 break;
2978 default:
2979 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2980 }
2981 }
Calin Juravled0d48522014-11-04 16:40:20 +00002982}
2983
Calin Juravle9aec02f2014-11-18 23:06:35 +00002984void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2985 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2986
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002987 LocationSummary* locations =
2988 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002989
2990 switch (op->GetResultType()) {
2991 case Primitive::kPrimInt: {
2992 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00002993 if (op->InputAt(1)->IsConstant()) {
2994 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
2995 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2996 } else {
2997 locations->SetInAt(1, Location::RequiresRegister());
2998 // Make the output overlap, as it will be used to hold the masked
2999 // second input.
3000 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3001 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003002 break;
3003 }
3004 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003005 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003006 if (op->InputAt(1)->IsConstant()) {
3007 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
3008 // For simplicity, use kOutputOverlap even though we only require that low registers
3009 // don't clash with high registers which the register allocator currently guarantees.
3010 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3011 } else {
3012 locations->SetInAt(1, Location::RequiresRegister());
3013 locations->AddTemp(Location::RequiresRegister());
3014 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3015 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003016 break;
3017 }
3018 default:
3019 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
3020 }
3021}
3022
3023void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
3024 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3025
3026 LocationSummary* locations = op->GetLocations();
3027 Location out = locations->Out();
3028 Location first = locations->InAt(0);
3029 Location second = locations->InAt(1);
3030
3031 Primitive::Type type = op->GetResultType();
3032 switch (type) {
3033 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003034 Register out_reg = out.AsRegister<Register>();
3035 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003036 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003037 Register second_reg = second.AsRegister<Register>();
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003038 // Arm doesn't mask the shift count so we need to do it ourselves.
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003039 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003040 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003041 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003042 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003043 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003044 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01003045 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003046 }
3047 } else {
3048 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3049 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
3050 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
3051 __ Mov(out_reg, first_reg);
3052 } else if (op->IsShl()) {
3053 __ Lsl(out_reg, first_reg, shift_value);
3054 } else if (op->IsShr()) {
3055 __ Asr(out_reg, first_reg, shift_value);
3056 } else {
3057 __ Lsr(out_reg, first_reg, shift_value);
3058 }
3059 }
3060 break;
3061 }
3062 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003063 Register o_h = out.AsRegisterPairHigh<Register>();
3064 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003065
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003066 Register high = first.AsRegisterPairHigh<Register>();
3067 Register low = first.AsRegisterPairLow<Register>();
3068
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003069 if (second.IsRegister()) {
3070 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00003071
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003072 Register second_reg = second.AsRegister<Register>();
3073
3074 if (op->IsShl()) {
3075 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue));
3076 // Shift the high part
3077 __ Lsl(o_h, high, o_l);
3078 // Shift the low part and `or` what overflew on the high part
3079 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
3080 __ Lsr(temp, low, temp);
3081 __ orr(o_h, o_h, ShifterOperand(temp));
3082 // If the shift is > 32 bits, override the high part
3083 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
3084 __ it(PL);
3085 __ Lsl(o_h, low, temp, PL);
3086 // Shift the low part
3087 __ Lsl(o_l, low, o_l);
3088 } else if (op->IsShr()) {
3089 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
3090 // Shift the low part
3091 __ Lsr(o_l, low, o_h);
3092 // Shift the high part and `or` what underflew on the low part
3093 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3094 __ Lsl(temp, high, temp);
3095 __ orr(o_l, o_l, ShifterOperand(temp));
3096 // If the shift is > 32 bits, override the low part
3097 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3098 __ it(PL);
3099 __ Asr(o_l, high, temp, PL);
3100 // Shift the high part
3101 __ Asr(o_h, high, o_h);
3102 } else {
3103 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue));
3104 // same as Shr except we use `Lsr`s and not `Asr`s
3105 __ Lsr(o_l, low, o_h);
3106 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
3107 __ Lsl(temp, high, temp);
3108 __ orr(o_l, o_l, ShifterOperand(temp));
3109 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
3110 __ it(PL);
3111 __ Lsr(o_l, high, temp, PL);
3112 __ Lsr(o_h, high, o_h);
3113 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003114 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003115 // Register allocator doesn't create partial overlap.
3116 DCHECK_NE(o_l, high);
3117 DCHECK_NE(o_h, low);
3118 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
3119 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxLongShiftValue);
3120 if (shift_value > 32) {
3121 if (op->IsShl()) {
3122 __ Lsl(o_h, low, shift_value - 32);
3123 __ LoadImmediate(o_l, 0);
3124 } else if (op->IsShr()) {
3125 __ Asr(o_l, high, shift_value - 32);
3126 __ Asr(o_h, high, 31);
3127 } else {
3128 __ Lsr(o_l, high, shift_value - 32);
3129 __ LoadImmediate(o_h, 0);
3130 }
3131 } else if (shift_value == 32) {
3132 if (op->IsShl()) {
3133 __ mov(o_h, ShifterOperand(low));
3134 __ LoadImmediate(o_l, 0);
3135 } else if (op->IsShr()) {
3136 __ mov(o_l, ShifterOperand(high));
3137 __ Asr(o_h, high, 31);
3138 } else {
3139 __ mov(o_l, ShifterOperand(high));
3140 __ LoadImmediate(o_h, 0);
3141 }
3142 } else { // shift_value < 32
3143 if (op->IsShl()) {
3144 __ Lsl(o_h, high, shift_value);
3145 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
3146 __ Lsl(o_l, low, shift_value);
3147 } else if (op->IsShr()) {
3148 __ Lsr(o_l, low, shift_value);
3149 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3150 __ Asr(o_h, high, shift_value);
3151 } else {
3152 __ Lsr(o_l, low, shift_value);
3153 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
3154 __ Lsr(o_h, high, shift_value);
3155 }
3156 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003157 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003158 break;
3159 }
3160 default:
3161 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00003162 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003163 }
3164}
3165
3166void LocationsBuilderARM::VisitShl(HShl* shl) {
3167 HandleShift(shl);
3168}
3169
3170void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
3171 HandleShift(shl);
3172}
3173
3174void LocationsBuilderARM::VisitShr(HShr* shr) {
3175 HandleShift(shr);
3176}
3177
3178void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
3179 HandleShift(shr);
3180}
3181
3182void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
3183 HandleShift(ushr);
3184}
3185
3186void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
3187 HandleShift(ushr);
3188}
3189
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003190void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003191 LocationSummary* locations =
3192 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003193 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray729645a2015-11-19 13:29:02 +00003194 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3195 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003196 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003197}
3198
3199void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01003200 // Note: if heap poisoning is enabled, the entry point takes cares
3201 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003202 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003203 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003204 instruction->GetDexPc(),
3205 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003206}
3207
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003208void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3209 LocationSummary* locations =
3210 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3211 InvokeRuntimeCallingConvention calling_convention;
3212 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003213 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003214 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003215 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003216}
3217
3218void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3219 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003220 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003221 // Note: if heap poisoning is enabled, the entry point takes cares
3222 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003223 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003224 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003225 instruction->GetDexPc(),
3226 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003227}
3228
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003229void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003230 LocationSummary* locations =
3231 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003232 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3233 if (location.IsStackSlot()) {
3234 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3235 } else if (location.IsDoubleStackSlot()) {
3236 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003237 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003238 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003239}
3240
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003241void InstructionCodeGeneratorARM::VisitParameterValue(
3242 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003243 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003244}
3245
3246void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3247 LocationSummary* locations =
3248 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3249 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3250}
3251
3252void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3253 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003254}
3255
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003256void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003257 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003258 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003259 locations->SetInAt(0, Location::RequiresRegister());
3260 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003261}
3262
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003263void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3264 LocationSummary* locations = not_->GetLocations();
3265 Location out = locations->Out();
3266 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003267 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003268 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003269 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003270 break;
3271
3272 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003273 __ mvn(out.AsRegisterPairLow<Register>(),
3274 ShifterOperand(in.AsRegisterPairLow<Register>()));
3275 __ mvn(out.AsRegisterPairHigh<Register>(),
3276 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003277 break;
3278
3279 default:
3280 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3281 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003282}
3283
David Brazdil66d126e2015-04-03 16:02:44 +01003284void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3285 LocationSummary* locations =
3286 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3287 locations->SetInAt(0, Location::RequiresRegister());
3288 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3289}
3290
3291void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003292 LocationSummary* locations = bool_not->GetLocations();
3293 Location out = locations->Out();
3294 Location in = locations->InAt(0);
3295 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3296}
3297
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003298void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003299 LocationSummary* locations =
3300 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003301 switch (compare->InputAt(0)->GetType()) {
3302 case Primitive::kPrimLong: {
3303 locations->SetInAt(0, Location::RequiresRegister());
3304 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003305 // Output overlaps because it is written before doing the low comparison.
3306 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003307 break;
3308 }
3309 case Primitive::kPrimFloat:
3310 case Primitive::kPrimDouble: {
3311 locations->SetInAt(0, Location::RequiresFpuRegister());
3312 locations->SetInAt(1, Location::RequiresFpuRegister());
3313 locations->SetOut(Location::RequiresRegister());
3314 break;
3315 }
3316 default:
3317 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3318 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003319}
3320
3321void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003322 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003323 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003324 Location left = locations->InAt(0);
3325 Location right = locations->InAt(1);
3326
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003327 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003328 Primitive::Type type = compare->InputAt(0)->GetType();
3329 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003330 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003331 __ cmp(left.AsRegisterPairHigh<Register>(),
3332 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003333 __ b(&less, LT);
3334 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003335 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003336 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003337 __ cmp(left.AsRegisterPairLow<Register>(),
3338 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00003339 break;
3340 }
3341 case Primitive::kPrimFloat:
3342 case Primitive::kPrimDouble: {
3343 __ LoadImmediate(out, 0);
3344 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003345 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003346 } else {
3347 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3348 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3349 }
3350 __ vmstat(); // transfer FP status register to ARM APSR.
3351 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003352 break;
3353 }
3354 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003355 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003356 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003357 __ b(&done, EQ);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003358 __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats.
Calin Juravleddb7df22014-11-25 20:56:51 +00003359
3360 __ Bind(&greater);
3361 __ LoadImmediate(out, 1);
3362 __ b(&done);
3363
3364 __ Bind(&less);
3365 __ LoadImmediate(out, -1);
3366
3367 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003368}
3369
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003370void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003371 LocationSummary* locations =
3372 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003373 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3374 locations->SetInAt(i, Location::Any());
3375 }
3376 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003377}
3378
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003379void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003380 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003381}
3382
Calin Juravle52c48962014-12-16 17:02:57 +00003383void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3384 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07003385 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00003386 switch (kind) {
3387 case MemBarrierKind::kAnyStore:
3388 case MemBarrierKind::kLoadAny:
3389 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003390 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003391 break;
3392 }
3393 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003394 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003395 break;
3396 }
3397 default:
3398 LOG(FATAL) << "Unexpected memory barrier " << kind;
3399 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003400 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003401}
3402
3403void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3404 uint32_t offset,
3405 Register out_lo,
3406 Register out_hi) {
3407 if (offset != 0) {
3408 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003409 __ add(IP, addr, ShifterOperand(out_lo));
3410 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003411 }
3412 __ ldrexd(out_lo, out_hi, addr);
3413}
3414
3415void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3416 uint32_t offset,
3417 Register value_lo,
3418 Register value_hi,
3419 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003420 Register temp2,
3421 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003422 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003423 if (offset != 0) {
3424 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003425 __ add(IP, addr, ShifterOperand(temp1));
3426 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003427 }
3428 __ Bind(&fail);
3429 // We need a load followed by store. (The address used in a STREX instruction must
3430 // be the same as the address in the most recently executed LDREX instruction.)
3431 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003432 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003433 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003434 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003435}
3436
3437void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3438 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3439
Nicolas Geoffray39468442014-09-02 15:17:15 +01003440 LocationSummary* locations =
3441 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003442 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003443
Calin Juravle52c48962014-12-16 17:02:57 +00003444 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003445 if (Primitive::IsFloatingPointType(field_type)) {
3446 locations->SetInAt(1, Location::RequiresFpuRegister());
3447 } else {
3448 locations->SetInAt(1, Location::RequiresRegister());
3449 }
3450
Calin Juravle52c48962014-12-16 17:02:57 +00003451 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003452 bool generate_volatile = field_info.IsVolatile()
3453 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003454 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003455 bool needs_write_barrier =
3456 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003457 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003458 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003459 if (needs_write_barrier) {
3460 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003461 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003462 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00003463 // Arm encoding have some additional constraints for ldrexd/strexd:
3464 // - registers need to be consecutive
3465 // - the first register should be even but not R14.
3466 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3467 // enable Arm encoding.
3468 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3469
3470 locations->AddTemp(Location::RequiresRegister());
3471 locations->AddTemp(Location::RequiresRegister());
3472 if (field_type == Primitive::kPrimDouble) {
3473 // For doubles we need two more registers to copy the value.
3474 locations->AddTemp(Location::RegisterLocation(R2));
3475 locations->AddTemp(Location::RegisterLocation(R3));
3476 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003477 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003478}
3479
Calin Juravle52c48962014-12-16 17:02:57 +00003480void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003481 const FieldInfo& field_info,
3482 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003483 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3484
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003485 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003486 Register base = locations->InAt(0).AsRegister<Register>();
3487 Location value = locations->InAt(1);
3488
3489 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003490 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003491 Primitive::Type field_type = field_info.GetFieldType();
3492 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003493 bool needs_write_barrier =
3494 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003495
3496 if (is_volatile) {
3497 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3498 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003499
3500 switch (field_type) {
3501 case Primitive::kPrimBoolean:
3502 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003503 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003504 break;
3505 }
3506
3507 case Primitive::kPrimShort:
3508 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003509 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003510 break;
3511 }
3512
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003513 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003514 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003515 if (kPoisonHeapReferences && needs_write_barrier) {
3516 // Note that in the case where `value` is a null reference,
3517 // we do not enter this block, as a null reference does not
3518 // need poisoning.
3519 DCHECK_EQ(field_type, Primitive::kPrimNot);
3520 Register temp = locations->GetTemp(0).AsRegister<Register>();
3521 __ Mov(temp, value.AsRegister<Register>());
3522 __ PoisonHeapReference(temp);
3523 __ StoreToOffset(kStoreWord, temp, base, offset);
3524 } else {
3525 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3526 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003527 break;
3528 }
3529
3530 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003531 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003532 GenerateWideAtomicStore(base, offset,
3533 value.AsRegisterPairLow<Register>(),
3534 value.AsRegisterPairHigh<Register>(),
3535 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003536 locations->GetTemp(1).AsRegister<Register>(),
3537 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003538 } else {
3539 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003540 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003541 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003542 break;
3543 }
3544
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003545 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003546 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003547 break;
3548 }
3549
3550 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003551 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003552 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003553 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3554 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3555
3556 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3557
3558 GenerateWideAtomicStore(base, offset,
3559 value_reg_lo,
3560 value_reg_hi,
3561 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003562 locations->GetTemp(3).AsRegister<Register>(),
3563 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003564 } else {
3565 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003566 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003567 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003568 break;
3569 }
3570
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003571 case Primitive::kPrimVoid:
3572 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003573 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003574 }
Calin Juravle52c48962014-12-16 17:02:57 +00003575
Calin Juravle77520bc2015-01-12 18:45:46 +00003576 // Longs and doubles are handled in the switch.
3577 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3578 codegen_->MaybeRecordImplicitNullCheck(instruction);
3579 }
3580
3581 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3582 Register temp = locations->GetTemp(0).AsRegister<Register>();
3583 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003584 codegen_->MarkGCCard(
3585 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003586 }
3587
Calin Juravle52c48962014-12-16 17:02:57 +00003588 if (is_volatile) {
3589 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3590 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003591}
3592
Calin Juravle52c48962014-12-16 17:02:57 +00003593void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3594 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003595 LocationSummary* locations =
3596 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003597 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003598
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003599 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003600 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003601 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003602 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003603
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003604 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3605 locations->SetOut(Location::RequiresFpuRegister());
3606 } else {
3607 locations->SetOut(Location::RequiresRegister(),
3608 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3609 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003610 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00003611 // Arm encoding have some additional constraints for ldrexd/strexd:
3612 // - registers need to be consecutive
3613 // - the first register should be even but not R14.
3614 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3615 // enable Arm encoding.
3616 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3617 locations->AddTemp(Location::RequiresRegister());
3618 locations->AddTemp(Location::RequiresRegister());
3619 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003620}
3621
Vladimir Markod2b4ca22015-09-14 15:13:26 +01003622Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
3623 Opcode opcode) {
3624 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
3625 if (constant->IsConstant() &&
3626 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
3627 return Location::ConstantLocation(constant->AsConstant());
3628 }
3629 return Location::RequiresRegister();
3630}
3631
3632bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
3633 Opcode opcode) {
3634 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
3635 if (Primitive::Is64BitType(input_cst->GetType())) {
3636 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
3637 CanEncodeConstantAsImmediate(High32Bits(value), opcode);
3638 } else {
3639 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
3640 }
3641}
3642
3643bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
3644 ShifterOperand so;
3645 ArmAssembler* assembler = codegen_->GetAssembler();
3646 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
3647 return true;
3648 }
3649 Opcode neg_opcode = kNoOperand;
3650 switch (opcode) {
3651 case AND:
3652 neg_opcode = BIC;
3653 break;
3654 case ORR:
3655 neg_opcode = ORN;
3656 break;
3657 default:
3658 return false;
3659 }
3660 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
3661}
3662
Calin Juravle52c48962014-12-16 17:02:57 +00003663void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
3664 const FieldInfo& field_info) {
3665 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003666
Calin Juravle52c48962014-12-16 17:02:57 +00003667 LocationSummary* locations = instruction->GetLocations();
3668 Register base = locations->InAt(0).AsRegister<Register>();
3669 Location out = locations->Out();
3670 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003671 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003672 Primitive::Type field_type = field_info.GetFieldType();
3673 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3674
3675 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003676 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003677 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003678 break;
3679 }
3680
3681 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003682 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003683 break;
3684 }
3685
3686 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003687 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003688 break;
3689 }
3690
3691 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003692 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003693 break;
3694 }
3695
3696 case Primitive::kPrimInt:
3697 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003698 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003699 break;
3700 }
3701
3702 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003703 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003704 GenerateWideAtomicLoad(base, offset,
3705 out.AsRegisterPairLow<Register>(),
3706 out.AsRegisterPairHigh<Register>());
3707 } else {
3708 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3709 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003710 break;
3711 }
3712
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003713 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003714 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003715 break;
3716 }
3717
3718 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003719 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003720 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003721 Register lo = locations->GetTemp(0).AsRegister<Register>();
3722 Register hi = locations->GetTemp(1).AsRegister<Register>();
3723 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003724 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003725 __ vmovdrr(out_reg, lo, hi);
3726 } else {
3727 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003728 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003729 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003730 break;
3731 }
3732
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003733 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003734 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003735 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003736 }
Calin Juravle52c48962014-12-16 17:02:57 +00003737
Calin Juravle77520bc2015-01-12 18:45:46 +00003738 // Doubles are handled in the switch.
3739 if (field_type != Primitive::kPrimDouble) {
3740 codegen_->MaybeRecordImplicitNullCheck(instruction);
3741 }
3742
Calin Juravle52c48962014-12-16 17:02:57 +00003743 if (is_volatile) {
3744 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3745 }
Roland Levillain4d027112015-07-01 15:41:14 +01003746
3747 if (field_type == Primitive::kPrimNot) {
3748 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3749 }
Calin Juravle52c48962014-12-16 17:02:57 +00003750}
3751
3752void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3753 HandleFieldSet(instruction, instruction->GetFieldInfo());
3754}
3755
3756void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003757 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003758}
3759
3760void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3761 HandleFieldGet(instruction, instruction->GetFieldInfo());
3762}
3763
3764void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3765 HandleFieldGet(instruction, instruction->GetFieldInfo());
3766}
3767
3768void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3769 HandleFieldGet(instruction, instruction->GetFieldInfo());
3770}
3771
3772void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3773 HandleFieldGet(instruction, instruction->GetFieldInfo());
3774}
3775
3776void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3777 HandleFieldSet(instruction, instruction->GetFieldInfo());
3778}
3779
3780void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003781 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003782}
3783
Calin Juravlee460d1d2015-09-29 04:52:17 +01003784void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
3785 HUnresolvedInstanceFieldGet* instruction) {
3786 FieldAccessCallingConventionARM calling_convention;
3787 codegen_->CreateUnresolvedFieldLocationSummary(
3788 instruction, instruction->GetFieldType(), calling_convention);
3789}
3790
3791void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
3792 HUnresolvedInstanceFieldGet* instruction) {
3793 FieldAccessCallingConventionARM calling_convention;
3794 codegen_->GenerateUnresolvedFieldAccess(instruction,
3795 instruction->GetFieldType(),
3796 instruction->GetFieldIndex(),
3797 instruction->GetDexPc(),
3798 calling_convention);
3799}
3800
3801void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
3802 HUnresolvedInstanceFieldSet* instruction) {
3803 FieldAccessCallingConventionARM calling_convention;
3804 codegen_->CreateUnresolvedFieldLocationSummary(
3805 instruction, instruction->GetFieldType(), calling_convention);
3806}
3807
3808void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
3809 HUnresolvedInstanceFieldSet* instruction) {
3810 FieldAccessCallingConventionARM calling_convention;
3811 codegen_->GenerateUnresolvedFieldAccess(instruction,
3812 instruction->GetFieldType(),
3813 instruction->GetFieldIndex(),
3814 instruction->GetDexPc(),
3815 calling_convention);
3816}
3817
3818void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
3819 HUnresolvedStaticFieldGet* instruction) {
3820 FieldAccessCallingConventionARM calling_convention;
3821 codegen_->CreateUnresolvedFieldLocationSummary(
3822 instruction, instruction->GetFieldType(), calling_convention);
3823}
3824
3825void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
3826 HUnresolvedStaticFieldGet* instruction) {
3827 FieldAccessCallingConventionARM calling_convention;
3828 codegen_->GenerateUnresolvedFieldAccess(instruction,
3829 instruction->GetFieldType(),
3830 instruction->GetFieldIndex(),
3831 instruction->GetDexPc(),
3832 calling_convention);
3833}
3834
3835void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
3836 HUnresolvedStaticFieldSet* instruction) {
3837 FieldAccessCallingConventionARM calling_convention;
3838 codegen_->CreateUnresolvedFieldLocationSummary(
3839 instruction, instruction->GetFieldType(), calling_convention);
3840}
3841
3842void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
3843 HUnresolvedStaticFieldSet* instruction) {
3844 FieldAccessCallingConventionARM calling_convention;
3845 codegen_->GenerateUnresolvedFieldAccess(instruction,
3846 instruction->GetFieldType(),
3847 instruction->GetFieldIndex(),
3848 instruction->GetDexPc(),
3849 calling_convention);
3850}
3851
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003852void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003853 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3854 ? LocationSummary::kCallOnSlowPath
3855 : LocationSummary::kNoCall;
3856 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00003857 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003858 if (instruction->HasUses()) {
3859 locations->SetOut(Location::SameAsFirstInput());
3860 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003861}
3862
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003863void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003864 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3865 return;
3866 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003867 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003868
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003869 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3870 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3871}
3872
3873void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003874 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003875 codegen_->AddSlowPath(slow_path);
3876
3877 LocationSummary* locations = instruction->GetLocations();
3878 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003879
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003880 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003881}
3882
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003883void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003884 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003885 GenerateImplicitNullCheck(instruction);
3886 } else {
3887 GenerateExplicitNullCheck(instruction);
3888 }
3889}
3890
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003891void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003892 LocationSummary* locations =
3893 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003894 locations->SetInAt(0, Location::RequiresRegister());
3895 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003896 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3897 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3898 } else {
3899 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3900 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003901}
3902
3903void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3904 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003905 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003906 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003907 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003908
Roland Levillain4d027112015-07-01 15:41:14 +01003909 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003910 case Primitive::kPrimBoolean: {
3911 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003912 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003913 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003914 size_t offset =
3915 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003916 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3917 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003918 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003919 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3920 }
3921 break;
3922 }
3923
3924 case Primitive::kPrimByte: {
3925 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003926 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003927 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003928 size_t offset =
3929 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003930 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3931 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003932 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003933 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3934 }
3935 break;
3936 }
3937
3938 case Primitive::kPrimShort: {
3939 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003940 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003941 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003942 size_t offset =
3943 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003944 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3945 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003946 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003947 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3948 }
3949 break;
3950 }
3951
3952 case Primitive::kPrimChar: {
3953 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003954 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003955 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003956 size_t offset =
3957 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003958 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3959 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003960 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003961 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3962 }
3963 break;
3964 }
3965
3966 case Primitive::kPrimInt:
3967 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003968 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3969 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003970 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003971 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003972 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003973 size_t offset =
3974 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003975 __ LoadFromOffset(kLoadWord, out, obj, offset);
3976 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003977 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003978 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3979 }
3980 break;
3981 }
3982
3983 case Primitive::kPrimLong: {
3984 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003985 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003986 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003987 size_t offset =
3988 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003989 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003990 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003991 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003992 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003993 }
3994 break;
3995 }
3996
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003997 case Primitive::kPrimFloat: {
3998 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3999 Location out = locations->Out();
4000 DCHECK(out.IsFpuRegister());
4001 if (index.IsConstant()) {
4002 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4003 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
4004 } else {
4005 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4006 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
4007 }
4008 break;
4009 }
4010
4011 case Primitive::kPrimDouble: {
4012 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4013 Location out = locations->Out();
4014 DCHECK(out.IsFpuRegisterPair());
4015 if (index.IsConstant()) {
4016 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4017 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
4018 } else {
4019 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4020 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4021 }
4022 break;
4023 }
4024
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004025 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004026 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004027 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004028 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004029 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004030
4031 if (type == Primitive::kPrimNot) {
4032 Register out = locations->Out().AsRegister<Register>();
4033 __ MaybeUnpoisonHeapReference(out);
4034 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004035}
4036
4037void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004038 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004039
4040 bool needs_write_barrier =
4041 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004042 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004043
Nicolas Geoffray39468442014-09-02 15:17:15 +01004044 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004045 instruction,
4046 may_need_runtime_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
4047 locations->SetInAt(0, Location::RequiresRegister());
4048 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4049 if (Primitive::IsFloatingPointType(value_type)) {
4050 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004051 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004052 locations->SetInAt(2, Location::RequiresRegister());
4053 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004054
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004055 if (needs_write_barrier) {
4056 // Temporary registers for the write barrier.
4057 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
4058 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004059 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004060}
4061
4062void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4063 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004064 Register array = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004065 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004066 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004067 bool may_need_runtime_call = locations->CanCall();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004068 bool needs_write_barrier =
4069 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004070
4071 switch (value_type) {
4072 case Primitive::kPrimBoolean:
4073 case Primitive::kPrimByte: {
4074 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004075 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004076 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004077 size_t offset =
4078 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004079 __ StoreToOffset(kStoreByte, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004080 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004081 __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004082 __ StoreToOffset(kStoreByte, value, IP, data_offset);
4083 }
4084 break;
4085 }
4086
4087 case Primitive::kPrimShort:
4088 case Primitive::kPrimChar: {
4089 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004090 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004091 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004092 size_t offset =
4093 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004094 __ StoreToOffset(kStoreHalfword, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004095 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004096 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004097 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4098 }
4099 break;
4100 }
4101
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004102 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004103 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4104 Register value = locations->InAt(2).AsRegister<Register>();
4105 Register source = value;
4106
4107 if (instruction->InputAt(2)->IsNullConstant()) {
4108 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004109 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004110 size_t offset =
4111 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004112 __ StoreToOffset(kStoreWord, source, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004113 } else {
4114 DCHECK(index.IsRegister()) << index;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004115 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01004116 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004117 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004118 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004119 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004120
4121 DCHECK(needs_write_barrier);
4122 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4123 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4124 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4125 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4126 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4127 Label done;
4128 SlowPathCode* slow_path = nullptr;
4129
4130 if (may_need_runtime_call) {
4131 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4132 codegen_->AddSlowPath(slow_path);
4133 if (instruction->GetValueCanBeNull()) {
4134 Label non_zero;
4135 __ CompareAndBranchIfNonZero(value, &non_zero);
4136 if (index.IsConstant()) {
4137 size_t offset =
4138 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4139 __ StoreToOffset(kStoreWord, value, array, offset);
4140 } else {
4141 DCHECK(index.IsRegister()) << index;
4142 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4143 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4144 }
4145 codegen_->MaybeRecordImplicitNullCheck(instruction);
4146 __ b(&done);
4147 __ Bind(&non_zero);
4148 }
4149
4150 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4151 codegen_->MaybeRecordImplicitNullCheck(instruction);
4152 __ MaybeUnpoisonHeapReference(temp1);
4153 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4154 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4155 // No need to poison/unpoison, we're comparing two poisoined references.
4156 __ cmp(temp1, ShifterOperand(temp2));
4157 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4158 Label do_put;
4159 __ b(&do_put, EQ);
4160 __ MaybeUnpoisonHeapReference(temp1);
4161 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4162 // No need to poison/unpoison, we're comparing against null.
4163 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4164 __ Bind(&do_put);
4165 } else {
4166 __ b(slow_path->GetEntryLabel(), NE);
4167 }
4168 }
4169
4170 if (kPoisonHeapReferences) {
4171 // Note that in the case where `value` is a null reference,
4172 // we do not enter this block, as a null reference does not
4173 // need poisoning.
4174 DCHECK_EQ(value_type, Primitive::kPrimNot);
4175 __ Mov(temp1, value);
4176 __ PoisonHeapReference(temp1);
4177 source = temp1;
4178 }
4179
4180 if (index.IsConstant()) {
4181 size_t offset =
4182 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4183 __ StoreToOffset(kStoreWord, source, array, offset);
4184 } else {
4185 DCHECK(index.IsRegister()) << index;
4186 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4187 __ StoreToOffset(kStoreWord, source, IP, data_offset);
4188 }
4189
4190 if (!may_need_runtime_call) {
4191 codegen_->MaybeRecordImplicitNullCheck(instruction);
4192 }
4193
4194 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4195
4196 if (done.IsLinked()) {
4197 __ Bind(&done);
4198 }
4199
4200 if (slow_path != nullptr) {
4201 __ Bind(slow_path->GetExitLabel());
4202 }
4203
4204 break;
4205 }
4206
4207 case Primitive::kPrimInt: {
4208 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4209 Register value = locations->InAt(2).AsRegister<Register>();
4210 if (index.IsConstant()) {
4211 size_t offset =
4212 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4213 __ StoreToOffset(kStoreWord, value, array, offset);
4214 } else {
4215 DCHECK(index.IsRegister()) << index;
4216 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4217 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4218 }
4219
4220 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004221 break;
4222 }
4223
4224 case Primitive::kPrimLong: {
4225 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004226 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004227 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004228 size_t offset =
4229 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004230 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004231 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004232 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004233 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004234 }
4235 break;
4236 }
4237
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004238 case Primitive::kPrimFloat: {
4239 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4240 Location value = locations->InAt(2);
4241 DCHECK(value.IsFpuRegister());
4242 if (index.IsConstant()) {
4243 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004244 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004245 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004246 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004247 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4248 }
4249 break;
4250 }
4251
4252 case Primitive::kPrimDouble: {
4253 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4254 Location value = locations->InAt(2);
4255 DCHECK(value.IsFpuRegisterPair());
4256 if (index.IsConstant()) {
4257 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004258 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004259 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004260 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004261 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4262 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004263
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004264 break;
4265 }
4266
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004267 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004268 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004269 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004270 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004271
4272 // Ints and objects are handled in the switch.
4273 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
4274 codegen_->MaybeRecordImplicitNullCheck(instruction);
4275 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004276}
4277
4278void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004279 LocationSummary* locations =
4280 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004281 locations->SetInAt(0, Location::RequiresRegister());
4282 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004283}
4284
4285void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4286 LocationSummary* locations = instruction->GetLocations();
4287 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004288 Register obj = locations->InAt(0).AsRegister<Register>();
4289 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004290 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004291 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004292}
4293
4294void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004295 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4296 ? LocationSummary::kCallOnSlowPath
4297 : LocationSummary::kNoCall;
4298 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004299 locations->SetInAt(0, Location::RequiresRegister());
4300 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004301 if (instruction->HasUses()) {
4302 locations->SetOut(Location::SameAsFirstInput());
4303 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004304}
4305
4306void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4307 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004308 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004309 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004310 codegen_->AddSlowPath(slow_path);
4311
Roland Levillain271ab9c2014-11-27 15:23:57 +00004312 Register index = locations->InAt(0).AsRegister<Register>();
4313 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004314
4315 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004316 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004317}
4318
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004319void CodeGeneratorARM::MarkGCCard(Register temp,
4320 Register card,
4321 Register object,
4322 Register value,
4323 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004324 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004325 if (can_be_null) {
4326 __ CompareAndBranchIfZero(value, &is_null);
4327 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004328 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4329 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4330 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004331 if (can_be_null) {
4332 __ Bind(&is_null);
4333 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004334}
4335
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004336void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
4337 temp->SetLocations(nullptr);
4338}
4339
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004340void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004341 // Nothing to do, this is driven by the code generator.
4342}
4343
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004344void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004345 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004346}
4347
4348void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004349 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4350}
4351
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004352void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4353 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4354}
4355
4356void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004357 HBasicBlock* block = instruction->GetBlock();
4358 if (block->GetLoopInformation() != nullptr) {
4359 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4360 // The back edge will generate the suspend check.
4361 return;
4362 }
4363 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4364 // The goto will generate the suspend check.
4365 return;
4366 }
4367 GenerateSuspendCheck(instruction, nullptr);
4368}
4369
4370void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4371 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004372 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004373 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4374 if (slow_path == nullptr) {
4375 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4376 instruction->SetSlowPath(slow_path);
4377 codegen_->AddSlowPath(slow_path);
4378 if (successor != nullptr) {
4379 DCHECK(successor->IsLoopHeader());
4380 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4381 }
4382 } else {
4383 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4384 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004385
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004386 __ LoadFromOffset(
4387 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004388 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004389 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004390 __ Bind(slow_path->GetReturnLabel());
4391 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004392 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004393 __ b(slow_path->GetEntryLabel());
4394 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004395}
4396
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004397ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4398 return codegen_->GetAssembler();
4399}
4400
4401void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004402 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004403 Location source = move->GetSource();
4404 Location destination = move->GetDestination();
4405
4406 if (source.IsRegister()) {
4407 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004408 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004409 } else {
4410 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004411 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004412 SP, destination.GetStackIndex());
4413 }
4414 } else if (source.IsStackSlot()) {
4415 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004416 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004417 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004418 } else if (destination.IsFpuRegister()) {
4419 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004420 } else {
4421 DCHECK(destination.IsStackSlot());
4422 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4423 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4424 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004425 } else if (source.IsFpuRegister()) {
4426 if (destination.IsFpuRegister()) {
4427 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004428 } else {
4429 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004430 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4431 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004432 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004433 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004434 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4435 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004436 } else if (destination.IsRegisterPair()) {
4437 DCHECK(ExpectedPairLayout(destination));
4438 __ LoadFromOffset(
4439 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4440 } else {
4441 DCHECK(destination.IsFpuRegisterPair()) << destination;
4442 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4443 SP,
4444 source.GetStackIndex());
4445 }
4446 } else if (source.IsRegisterPair()) {
4447 if (destination.IsRegisterPair()) {
4448 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4449 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4450 } else {
4451 DCHECK(destination.IsDoubleStackSlot()) << destination;
4452 DCHECK(ExpectedPairLayout(source));
4453 __ StoreToOffset(
4454 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4455 }
4456 } else if (source.IsFpuRegisterPair()) {
4457 if (destination.IsFpuRegisterPair()) {
4458 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4459 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4460 } else {
4461 DCHECK(destination.IsDoubleStackSlot()) << destination;
4462 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4463 SP,
4464 destination.GetStackIndex());
4465 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004466 } else {
4467 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004468 HConstant* constant = source.GetConstant();
4469 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4470 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004471 if (destination.IsRegister()) {
4472 __ LoadImmediate(destination.AsRegister<Register>(), value);
4473 } else {
4474 DCHECK(destination.IsStackSlot());
4475 __ LoadImmediate(IP, value);
4476 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4477 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004478 } else if (constant->IsLongConstant()) {
4479 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004480 if (destination.IsRegisterPair()) {
4481 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4482 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004483 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004484 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004485 __ LoadImmediate(IP, Low32Bits(value));
4486 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4487 __ LoadImmediate(IP, High32Bits(value));
4488 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4489 }
4490 } else if (constant->IsDoubleConstant()) {
4491 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004492 if (destination.IsFpuRegisterPair()) {
4493 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004494 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004495 DCHECK(destination.IsDoubleStackSlot()) << destination;
4496 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004497 __ LoadImmediate(IP, Low32Bits(int_value));
4498 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4499 __ LoadImmediate(IP, High32Bits(int_value));
4500 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4501 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004502 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004503 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004504 float value = constant->AsFloatConstant()->GetValue();
4505 if (destination.IsFpuRegister()) {
4506 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4507 } else {
4508 DCHECK(destination.IsStackSlot());
4509 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4510 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4511 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004512 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004513 }
4514}
4515
4516void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4517 __ Mov(IP, reg);
4518 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4519 __ StoreToOffset(kStoreWord, IP, SP, mem);
4520}
4521
4522void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4523 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4524 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4525 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4526 SP, mem1 + stack_offset);
4527 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4528 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4529 SP, mem2 + stack_offset);
4530 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
4531}
4532
4533void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004534 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004535 Location source = move->GetSource();
4536 Location destination = move->GetDestination();
4537
4538 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004539 DCHECK_NE(source.AsRegister<Register>(), IP);
4540 DCHECK_NE(destination.AsRegister<Register>(), IP);
4541 __ Mov(IP, source.AsRegister<Register>());
4542 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
4543 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004544 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004545 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004546 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004547 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004548 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4549 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004550 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004551 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004552 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004553 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004554 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004555 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004556 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004557 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004558 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4559 destination.AsRegisterPairHigh<Register>(),
4560 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004561 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004562 Register low_reg = source.IsRegisterPair()
4563 ? source.AsRegisterPairLow<Register>()
4564 : destination.AsRegisterPairLow<Register>();
4565 int mem = source.IsRegisterPair()
4566 ? destination.GetStackIndex()
4567 : source.GetStackIndex();
4568 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004569 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004570 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004571 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004572 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004573 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
4574 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004575 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004576 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004577 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004578 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
4579 DRegister reg = source.IsFpuRegisterPair()
4580 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
4581 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
4582 int mem = source.IsFpuRegisterPair()
4583 ? destination.GetStackIndex()
4584 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004585 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004586 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004587 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004588 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
4589 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
4590 : destination.AsFpuRegister<SRegister>();
4591 int mem = source.IsFpuRegister()
4592 ? destination.GetStackIndex()
4593 : source.GetStackIndex();
4594
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004595 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004596 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004597 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004598 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004599 Exchange(source.GetStackIndex(), destination.GetStackIndex());
4600 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004601 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004602 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004603 }
4604}
4605
4606void ParallelMoveResolverARM::SpillScratch(int reg) {
4607 __ Push(static_cast<Register>(reg));
4608}
4609
4610void ParallelMoveResolverARM::RestoreScratch(int reg) {
4611 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004612}
4613
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004614void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01004615 InvokeRuntimeCallingConvention calling_convention;
4616 CodeGenerator::CreateLoadClassLocationSummary(
4617 cls,
4618 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
4619 Location::RegisterLocation(R0));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004620}
4621
4622void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004623 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01004624 if (cls->NeedsAccessCheck()) {
4625 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
4626 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
4627 cls,
4628 cls->GetDexPc(),
4629 nullptr);
Calin Juravle580b6092015-10-06 17:35:58 +01004630 return;
4631 }
4632
4633 Register out = locations->Out().AsRegister<Register>();
4634 Register current_method = locations->InAt(0).AsRegister<Register>();
4635 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004636 DCHECK(!cls->CanCallRuntime());
4637 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004638 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004639 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004640 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004641 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004642 __ LoadFromOffset(kLoadWord,
4643 out,
4644 current_method,
Vladimir Marko05792b92015-08-03 11:56:49 +01004645 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004646 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004647 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004648
Andreas Gampe85b62f22015-09-09 13:15:38 -07004649 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004650 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4651 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004652 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004653 if (cls->MustGenerateClinitCheck()) {
4654 GenerateClassInitializationCheck(slow_path, out);
4655 } else {
4656 __ Bind(slow_path->GetExitLabel());
4657 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004658 }
4659}
4660
4661void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
4662 LocationSummary* locations =
4663 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4664 locations->SetInAt(0, Location::RequiresRegister());
4665 if (check->HasUses()) {
4666 locations->SetOut(Location::SameAsFirstInput());
4667 }
4668}
4669
4670void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004671 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07004672 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004673 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004674 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004675 GenerateClassInitializationCheck(slow_path,
4676 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004677}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004678
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004679void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07004680 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004681 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
4682 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
4683 __ b(slow_path->GetEntryLabel(), LT);
4684 // Even if the initialized flag is set, we may be in a situation where caches are not synced
4685 // properly. Therefore, we do a memory fence.
4686 __ dmb(ISH);
4687 __ Bind(slow_path->GetExitLabel());
4688}
4689
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004690void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
4691 LocationSummary* locations =
4692 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004693 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004694 locations->SetOut(Location::RequiresRegister());
4695}
4696
4697void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004698 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004699 codegen_->AddSlowPath(slow_path);
4700
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004701 LocationSummary* locations = load->GetLocations();
4702 Register out = locations->Out().AsRegister<Register>();
4703 Register current_method = locations->InAt(0).AsRegister<Register>();
4704 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004705 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Mathieu Chartiereace4582014-11-24 18:29:54 -08004706 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004707 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004708 // TODO: We will need a read barrier here.
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004709 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004710 __ Bind(slow_path->GetExitLabel());
4711}
4712
David Brazdilcb1c0552015-08-04 16:22:25 +01004713static int32_t GetExceptionTlsOffset() {
4714 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
4715}
4716
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004717void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
4718 LocationSummary* locations =
4719 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4720 locations->SetOut(Location::RequiresRegister());
4721}
4722
4723void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004724 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01004725 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
4726}
4727
4728void LocationsBuilderARM::VisitClearException(HClearException* clear) {
4729 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4730}
4731
4732void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004733 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01004734 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004735}
4736
4737void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
4738 LocationSummary* locations =
4739 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4740 InvokeRuntimeCallingConvention calling_convention;
4741 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4742}
4743
4744void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
4745 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004746 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004747}
4748
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004749void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004750 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4751 switch (instruction->GetTypeCheckKind()) {
4752 case TypeCheckKind::kExactCheck:
4753 case TypeCheckKind::kAbstractClassCheck:
4754 case TypeCheckKind::kClassHierarchyCheck:
4755 case TypeCheckKind::kArrayObjectCheck:
4756 call_kind = LocationSummary::kNoCall;
4757 break;
Calin Juravle98893e12015-10-02 21:05:03 +01004758 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004759 case TypeCheckKind::kInterfaceCheck:
4760 call_kind = LocationSummary::kCall;
4761 break;
4762 case TypeCheckKind::kArrayCheck:
4763 call_kind = LocationSummary::kCallOnSlowPath;
4764 break;
4765 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004766 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004767 if (call_kind != LocationSummary::kCall) {
4768 locations->SetInAt(0, Location::RequiresRegister());
4769 locations->SetInAt(1, Location::RequiresRegister());
4770 // The out register is used as a temporary, so it overlaps with the inputs.
4771 // Note that TypeCheckSlowPathARM uses this register too.
4772 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4773 } else {
4774 InvokeRuntimeCallingConvention calling_convention;
4775 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4776 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4777 locations->SetOut(Location::RegisterLocation(R0));
4778 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004779}
4780
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004781void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004782 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004783 Register obj = locations->InAt(0).AsRegister<Register>();
4784 Register cls = locations->InAt(1).AsRegister<Register>();
4785 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004786 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004787 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4788 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4789 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004790 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07004791 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004792
4793 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004794 // avoid null check if we know obj is not null.
4795 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00004796 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004797 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004798
Calin Juravle98893e12015-10-02 21:05:03 +01004799 // In case of an interface/unresolved check, we put the object class into the object register.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004800 // This is safe, as the register is caller-save, and the object must be in another
4801 // register if it survives the runtime call.
Calin Juravle98893e12015-10-02 21:05:03 +01004802 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
4803 (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004804 ? obj
4805 : out;
4806 __ LoadFromOffset(kLoadWord, target, obj, class_offset);
4807 __ MaybeUnpoisonHeapReference(target);
4808
4809 switch (instruction->GetTypeCheckKind()) {
4810 case TypeCheckKind::kExactCheck: {
4811 __ cmp(out, ShifterOperand(cls));
4812 // Classes must be equal for the instanceof to succeed.
4813 __ b(&zero, NE);
4814 __ LoadImmediate(out, 1);
4815 __ b(&done);
4816 break;
4817 }
4818 case TypeCheckKind::kAbstractClassCheck: {
4819 // If the class is abstract, we eagerly fetch the super class of the
4820 // object to avoid doing a comparison we know will fail.
4821 Label loop;
4822 __ Bind(&loop);
4823 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4824 __ MaybeUnpoisonHeapReference(out);
4825 // If `out` is null, we use it for the result, and jump to `done`.
4826 __ CompareAndBranchIfZero(out, &done);
4827 __ cmp(out, ShifterOperand(cls));
4828 __ b(&loop, NE);
4829 __ LoadImmediate(out, 1);
4830 if (zero.IsLinked()) {
4831 __ b(&done);
4832 }
4833 break;
4834 }
4835 case TypeCheckKind::kClassHierarchyCheck: {
4836 // Walk over the class hierarchy to find a match.
4837 Label loop, success;
4838 __ Bind(&loop);
4839 __ cmp(out, ShifterOperand(cls));
4840 __ b(&success, EQ);
4841 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4842 __ MaybeUnpoisonHeapReference(out);
4843 __ CompareAndBranchIfNonZero(out, &loop);
4844 // If `out` is null, we use it for the result, and jump to `done`.
4845 __ b(&done);
4846 __ Bind(&success);
4847 __ LoadImmediate(out, 1);
4848 if (zero.IsLinked()) {
4849 __ b(&done);
4850 }
4851 break;
4852 }
4853 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004854 // Do an exact check.
4855 Label exact_check;
4856 __ cmp(out, ShifterOperand(cls));
4857 __ b(&exact_check, EQ);
4858 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004859 __ LoadFromOffset(kLoadWord, out, out, component_offset);
4860 __ MaybeUnpoisonHeapReference(out);
4861 // If `out` is null, we use it for the result, and jump to `done`.
4862 __ CompareAndBranchIfZero(out, &done);
4863 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
4864 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4865 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004866 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004867 __ LoadImmediate(out, 1);
4868 __ b(&done);
4869 break;
4870 }
4871 case TypeCheckKind::kArrayCheck: {
4872 __ cmp(out, ShifterOperand(cls));
4873 DCHECK(locations->OnlyCallsOnSlowPath());
4874 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4875 instruction, /* is_fatal */ false);
4876 codegen_->AddSlowPath(slow_path);
4877 __ b(slow_path->GetEntryLabel(), NE);
4878 __ LoadImmediate(out, 1);
4879 if (zero.IsLinked()) {
4880 __ b(&done);
4881 }
4882 break;
4883 }
Calin Juravle98893e12015-10-02 21:05:03 +01004884 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004885 case TypeCheckKind::kInterfaceCheck:
4886 default: {
4887 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
4888 instruction,
4889 instruction->GetDexPc(),
4890 nullptr);
4891 if (zero.IsLinked()) {
4892 __ b(&done);
4893 }
4894 break;
4895 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004896 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004897
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004898 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004899 __ Bind(&zero);
4900 __ LoadImmediate(out, 0);
4901 }
4902
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004903 if (done.IsLinked()) {
4904 __ Bind(&done);
4905 }
4906
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004907 if (slow_path != nullptr) {
4908 __ Bind(slow_path->GetExitLabel());
4909 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004910}
4911
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004912void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004913 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4914 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
4915
4916 switch (instruction->GetTypeCheckKind()) {
4917 case TypeCheckKind::kExactCheck:
4918 case TypeCheckKind::kAbstractClassCheck:
4919 case TypeCheckKind::kClassHierarchyCheck:
4920 case TypeCheckKind::kArrayObjectCheck:
4921 call_kind = throws_into_catch
4922 ? LocationSummary::kCallOnSlowPath
4923 : LocationSummary::kNoCall;
4924 break;
Calin Juravle98893e12015-10-02 21:05:03 +01004925 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004926 case TypeCheckKind::kInterfaceCheck:
4927 call_kind = LocationSummary::kCall;
4928 break;
4929 case TypeCheckKind::kArrayCheck:
4930 call_kind = LocationSummary::kCallOnSlowPath;
4931 break;
4932 }
4933
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004934 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004935 instruction, call_kind);
4936 if (call_kind != LocationSummary::kCall) {
4937 locations->SetInAt(0, Location::RequiresRegister());
4938 locations->SetInAt(1, Location::RequiresRegister());
4939 // Note that TypeCheckSlowPathARM uses this register too.
4940 locations->AddTemp(Location::RequiresRegister());
4941 } else {
4942 InvokeRuntimeCallingConvention calling_convention;
4943 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4944 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4945 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004946}
4947
4948void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
4949 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004950 Register obj = locations->InAt(0).AsRegister<Register>();
4951 Register cls = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004952 Register temp = locations->WillCall()
4953 ? Register(kNoRegister)
4954 : locations->GetTemp(0).AsRegister<Register>();
4955
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004956 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004957 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4958 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4959 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
4960 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004961
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004962 if (!locations->WillCall()) {
4963 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4964 instruction, !locations->CanCall());
4965 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray64acf302015-09-14 22:20:29 +01004966 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004967
4968 Label done;
4969 // Avoid null check if we know obj is not null.
4970 if (instruction->MustDoNullCheck()) {
4971 __ CompareAndBranchIfZero(obj, &done);
4972 }
4973
4974 if (locations->WillCall()) {
4975 __ LoadFromOffset(kLoadWord, obj, obj, class_offset);
4976 __ MaybeUnpoisonHeapReference(obj);
4977 } else {
4978 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
4979 __ MaybeUnpoisonHeapReference(temp);
4980 }
4981
4982 switch (instruction->GetTypeCheckKind()) {
4983 case TypeCheckKind::kExactCheck:
4984 case TypeCheckKind::kArrayCheck: {
4985 __ cmp(temp, ShifterOperand(cls));
4986 // Jump to slow path for throwing the exception or doing a
4987 // more involved array check.
4988 __ b(slow_path->GetEntryLabel(), NE);
4989 break;
4990 }
4991 case TypeCheckKind::kAbstractClassCheck: {
4992 // If the class is abstract, we eagerly fetch the super class of the
4993 // object to avoid doing a comparison we know will fail.
4994 Label loop;
4995 __ Bind(&loop);
4996 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
4997 __ MaybeUnpoisonHeapReference(temp);
4998 // Jump to the slow path to throw the exception.
4999 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
5000 __ cmp(temp, ShifterOperand(cls));
5001 __ b(&loop, NE);
5002 break;
5003 }
5004 case TypeCheckKind::kClassHierarchyCheck: {
5005 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005006 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005007 __ Bind(&loop);
5008 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005009 __ b(&done, EQ);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005010 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
5011 __ MaybeUnpoisonHeapReference(temp);
5012 __ CompareAndBranchIfNonZero(temp, &loop);
5013 // Jump to the slow path to throw the exception.
5014 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005015 break;
5016 }
5017 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005018 // Do an exact check.
5019 __ cmp(temp, ShifterOperand(cls));
5020 __ b(&done, EQ);
5021 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005022 __ LoadFromOffset(kLoadWord, temp, temp, component_offset);
5023 __ MaybeUnpoisonHeapReference(temp);
5024 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
5025 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
5026 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5027 __ CompareAndBranchIfNonZero(temp, slow_path->GetEntryLabel());
5028 break;
5029 }
Calin Juravle98893e12015-10-02 21:05:03 +01005030 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005031 case TypeCheckKind::kInterfaceCheck:
5032 default:
5033 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
5034 instruction,
5035 instruction->GetDexPc(),
5036 nullptr);
5037 break;
5038 }
5039 __ Bind(&done);
5040
5041 if (slow_path != nullptr) {
5042 __ Bind(slow_path->GetExitLabel());
5043 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005044}
5045
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005046void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5047 LocationSummary* locations =
5048 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5049 InvokeRuntimeCallingConvention calling_convention;
5050 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5051}
5052
5053void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5054 codegen_->InvokeRuntime(instruction->IsEnter()
5055 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5056 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005057 instruction->GetDexPc(),
5058 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005059}
5060
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005061void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5062void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5063void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005064
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005065void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005066 LocationSummary* locations =
5067 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5068 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5069 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005070 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005071 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005072 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005073 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005074}
5075
5076void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5077 HandleBitwiseOperation(instruction);
5078}
5079
5080void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5081 HandleBitwiseOperation(instruction);
5082}
5083
5084void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5085 HandleBitwiseOperation(instruction);
5086}
5087
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005088void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5089 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5090 if (value == 0xffffffffu) {
5091 if (out != first) {
5092 __ mov(out, ShifterOperand(first));
5093 }
5094 return;
5095 }
5096 if (value == 0u) {
5097 __ mov(out, ShifterOperand(0));
5098 return;
5099 }
5100 ShifterOperand so;
5101 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5102 __ and_(out, first, so);
5103 } else {
5104 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5105 __ bic(out, first, ShifterOperand(~value));
5106 }
5107}
5108
5109void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5110 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5111 if (value == 0u) {
5112 if (out != first) {
5113 __ mov(out, ShifterOperand(first));
5114 }
5115 return;
5116 }
5117 if (value == 0xffffffffu) {
5118 __ mvn(out, ShifterOperand(0));
5119 return;
5120 }
5121 ShifterOperand so;
5122 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5123 __ orr(out, first, so);
5124 } else {
5125 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5126 __ orn(out, first, ShifterOperand(~value));
5127 }
5128}
5129
5130void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
5131 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
5132 if (value == 0u) {
5133 if (out != first) {
5134 __ mov(out, ShifterOperand(first));
5135 }
5136 return;
5137 }
5138 __ eor(out, first, ShifterOperand(value));
5139}
5140
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005141void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
5142 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005143 Location first = locations->InAt(0);
5144 Location second = locations->InAt(1);
5145 Location out = locations->Out();
5146
5147 if (second.IsConstant()) {
5148 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
5149 uint32_t value_low = Low32Bits(value);
5150 if (instruction->GetResultType() == Primitive::kPrimInt) {
5151 Register first_reg = first.AsRegister<Register>();
5152 Register out_reg = out.AsRegister<Register>();
5153 if (instruction->IsAnd()) {
5154 GenerateAndConst(out_reg, first_reg, value_low);
5155 } else if (instruction->IsOr()) {
5156 GenerateOrrConst(out_reg, first_reg, value_low);
5157 } else {
5158 DCHECK(instruction->IsXor());
5159 GenerateEorConst(out_reg, first_reg, value_low);
5160 }
5161 } else {
5162 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5163 uint32_t value_high = High32Bits(value);
5164 Register first_low = first.AsRegisterPairLow<Register>();
5165 Register first_high = first.AsRegisterPairHigh<Register>();
5166 Register out_low = out.AsRegisterPairLow<Register>();
5167 Register out_high = out.AsRegisterPairHigh<Register>();
5168 if (instruction->IsAnd()) {
5169 GenerateAndConst(out_low, first_low, value_low);
5170 GenerateAndConst(out_high, first_high, value_high);
5171 } else if (instruction->IsOr()) {
5172 GenerateOrrConst(out_low, first_low, value_low);
5173 GenerateOrrConst(out_high, first_high, value_high);
5174 } else {
5175 DCHECK(instruction->IsXor());
5176 GenerateEorConst(out_low, first_low, value_low);
5177 GenerateEorConst(out_high, first_high, value_high);
5178 }
5179 }
5180 return;
5181 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005182
5183 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005184 Register first_reg = first.AsRegister<Register>();
5185 ShifterOperand second_reg(second.AsRegister<Register>());
5186 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005187 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005188 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005189 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005190 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005191 } else {
5192 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005193 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005194 }
5195 } else {
5196 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005197 Register first_low = first.AsRegisterPairLow<Register>();
5198 Register first_high = first.AsRegisterPairHigh<Register>();
5199 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5200 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5201 Register out_low = out.AsRegisterPairLow<Register>();
5202 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005203 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005204 __ and_(out_low, first_low, second_low);
5205 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005206 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005207 __ orr(out_low, first_low, second_low);
5208 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005209 } else {
5210 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005211 __ eor(out_low, first_low, second_low);
5212 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005213 }
5214 }
5215}
5216
Vladimir Markodc151b22015-10-15 18:02:30 +01005217HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
5218 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
5219 MethodReference target_method) {
5220 if (desired_dispatch_info.method_load_kind ==
5221 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative) {
5222 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
5223 return HInvokeStaticOrDirect::DispatchInfo {
5224 HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod,
5225 HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
5226 0u,
5227 0u
5228 };
5229 }
5230 if (desired_dispatch_info.code_ptr_location ==
5231 HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
5232 const DexFile& outer_dex_file = GetGraph()->GetDexFile();
5233 if (&outer_dex_file != target_method.dex_file) {
5234 // Calls across dex files are more likely to exceed the available BL range,
5235 // so use absolute patch with fixup if available and kCallArtMethod otherwise.
5236 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
5237 (desired_dispatch_info.method_load_kind ==
5238 HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
5239 ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
5240 : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
5241 return HInvokeStaticOrDirect::DispatchInfo {
5242 desired_dispatch_info.method_load_kind,
5243 code_ptr_location,
5244 desired_dispatch_info.method_load_data,
5245 0u
5246 };
5247 }
5248 }
5249 return desired_dispatch_info;
5250}
5251
Nicolas Geoffray38207af2015-06-01 15:46:22 +01005252void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00005253 // For better instruction scheduling we load the direct code pointer before the method pointer.
Vladimir Marko58155012015-08-19 12:49:41 +00005254 switch (invoke->GetCodePtrLocation()) {
Vladimir Marko58155012015-08-19 12:49:41 +00005255 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
5256 // LR = code address from literal pool with link-time patch.
5257 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
Vladimir Marko58155012015-08-19 12:49:41 +00005258 break;
5259 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
5260 // LR = invoke->GetDirectCodePtr();
5261 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
Vladimir Marko58155012015-08-19 12:49:41 +00005262 break;
5263 default:
5264 break;
5265 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005266
Vladimir Marko58155012015-08-19 12:49:41 +00005267 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
5268 switch (invoke->GetMethodLoadKind()) {
5269 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
5270 // temp = thread->string_init_entrypoint
5271 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
5272 break;
5273 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
5274 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
5275 break;
5276 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
5277 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
5278 break;
5279 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
5280 __ LoadLiteral(temp.AsRegister<Register>(),
5281 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
5282 break;
5283 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01005284 // TODO: Implement this type.
5285 // Currently filtered out by GetSupportedInvokeStaticOrDirectDispatch().
5286 LOG(FATAL) << "Unsupported";
5287 UNREACHABLE();
Vladimir Marko58155012015-08-19 12:49:41 +00005288 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
5289 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
5290 Register method_reg;
5291 Register reg = temp.AsRegister<Register>();
5292 if (current_method.IsRegister()) {
5293 method_reg = current_method.AsRegister<Register>();
5294 } else {
5295 DCHECK(invoke->GetLocations()->Intrinsified());
5296 DCHECK(!current_method.IsValid());
5297 method_reg = reg;
5298 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
5299 }
5300 // temp = current_method->dex_cache_resolved_methods_;
5301 __ LoadFromOffset(
Vladimir Marko05792b92015-08-03 11:56:49 +01005302 kLoadWord, reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset(
5303 kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00005304 // temp = temp[index_in_cache]
5305 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
5306 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
5307 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01005308 }
Vladimir Marko58155012015-08-19 12:49:41 +00005309 }
5310
5311 switch (invoke->GetCodePtrLocation()) {
5312 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
5313 __ bl(GetFrameEntryLabel());
5314 break;
5315 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01005316 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005317 __ BindTrackedLabel(&relative_call_patches_.back().label);
Vladimir Markodc151b22015-10-15 18:02:30 +01005318 // Arbitrarily branch to the BL itself, override at link time.
5319 __ bl(&relative_call_patches_.back().label);
5320 break;
Vladimir Marko58155012015-08-19 12:49:41 +00005321 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
5322 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
5323 // LR prepared above for better instruction scheduling.
Vladimir Marko58155012015-08-19 12:49:41 +00005324 // LR()
5325 __ blx(LR);
5326 break;
5327 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
5328 // LR = callee_method->entry_point_from_quick_compiled_code_
5329 __ LoadFromOffset(
5330 kLoadWord, LR, callee_method.AsRegister<Register>(),
5331 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
5332 // LR()
5333 __ blx(LR);
5334 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005335 }
5336
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005337 DCHECK(!IsLeafMethod());
5338}
5339
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005340void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
5341 Register temp = temp_location.AsRegister<Register>();
5342 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5343 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
5344 LocationSummary* locations = invoke->GetLocations();
5345 Location receiver = locations->InAt(0);
5346 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5347 // temp = object->GetClass();
5348 DCHECK(receiver.IsRegister());
5349 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
5350 MaybeRecordImplicitNullCheck(invoke);
5351 __ MaybeUnpoisonHeapReference(temp);
5352 // temp = temp->GetMethodAt(method_offset);
5353 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
5354 kArmWordSize).Int32Value();
5355 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
5356 // LR = temp->GetEntryPoint();
5357 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
5358 // LR();
5359 __ blx(LR);
5360}
5361
Vladimir Marko58155012015-08-19 12:49:41 +00005362void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
5363 DCHECK(linker_patches->empty());
5364 size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
5365 linker_patches->reserve(size);
5366 for (const auto& entry : method_patches_) {
5367 const MethodReference& target_method = entry.first;
5368 Literal* literal = entry.second;
5369 DCHECK(literal->GetLabel()->IsBound());
5370 uint32_t literal_offset = literal->GetLabel()->Position();
5371 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
5372 target_method.dex_file,
5373 target_method.dex_method_index));
5374 }
5375 for (const auto& entry : call_patches_) {
5376 const MethodReference& target_method = entry.first;
5377 Literal* literal = entry.second;
5378 DCHECK(literal->GetLabel()->IsBound());
5379 uint32_t literal_offset = literal->GetLabel()->Position();
5380 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
5381 target_method.dex_file,
5382 target_method.dex_method_index));
5383 }
5384 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
5385 uint32_t literal_offset = info.label.Position();
5386 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
5387 info.target_method.dex_file,
5388 info.target_method.dex_method_index));
5389 }
5390}
5391
5392Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
5393 MethodToLiteralMap* map) {
5394 // Look up the literal for target_method.
5395 auto lb = map->lower_bound(target_method);
5396 if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
5397 return lb->second;
5398 }
5399 // We don't have a literal for this method yet, insert a new one.
5400 Literal* literal = __ NewLiteral<uint32_t>(0u);
5401 map->PutBefore(lb, target_method, literal);
5402 return literal;
5403}
5404
5405Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
5406 return DeduplicateMethodLiteral(target_method, &method_patches_);
5407}
5408
5409Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
5410 return DeduplicateMethodLiteral(target_method, &call_patches_);
5411}
5412
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005413void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005414 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005415 LOG(FATAL) << "Unreachable";
5416}
5417
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005418void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005419 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005420 LOG(FATAL) << "Unreachable";
5421}
5422
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005423void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
5424 DCHECK(codegen_->IsBaseline());
5425 LocationSummary* locations =
5426 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5427 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5428}
5429
5430void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5431 DCHECK(codegen_->IsBaseline());
5432 // Will be generated at use site.
5433}
5434
Mark Mendellfe57faa2015-09-18 09:26:15 -04005435// Simple implementation of packed switch - generate cascaded compare/jumps.
5436void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5437 LocationSummary* locations =
5438 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5439 locations->SetInAt(0, Location::RequiresRegister());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005440 if (switch_instr->GetNumEntries() >= kPackedSwitchJumpTableThreshold &&
5441 codegen_->GetAssembler()->IsThumb()) {
5442 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
5443 if (switch_instr->GetStartValue() != 0) {
5444 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
5445 }
5446 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04005447}
5448
5449void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5450 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005451 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04005452 LocationSummary* locations = switch_instr->GetLocations();
5453 Register value_reg = locations->InAt(0).AsRegister<Register>();
5454 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5455
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005456 if (num_entries < kPackedSwitchJumpTableThreshold || !codegen_->GetAssembler()->IsThumb()) {
5457 // Create a series of compare/jumps.
5458 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5459 for (uint32_t i = 0; i < num_entries; i++) {
5460 GenerateCompareWithImmediate(value_reg, lower_bound + i);
5461 __ b(codegen_->GetLabelOf(successors[i]), EQ);
5462 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04005463
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005464 // And the default for any other value.
5465 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5466 __ b(codegen_->GetLabelOf(default_block));
5467 }
5468 } else {
5469 // Create a table lookup.
5470 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
5471
5472 // Materialize a pointer to the switch table
5473 std::vector<Label*> labels(num_entries);
5474 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5475 for (uint32_t i = 0; i < num_entries; i++) {
5476 labels[i] = codegen_->GetLabelOf(successors[i]);
5477 }
5478 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
5479
5480 // Remove the bias.
5481 Register key_reg;
5482 if (lower_bound != 0) {
5483 key_reg = locations->GetTemp(1).AsRegister<Register>();
5484 __ AddConstant(key_reg, value_reg, -lower_bound);
5485 } else {
5486 key_reg = value_reg;
5487 }
5488
5489 // Check whether the value is in the table, jump to default block if not.
5490 __ CmpConstant(key_reg, num_entries - 1);
5491 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
5492
5493 // Load the displacement from the table.
5494 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
5495
5496 // Dispatch is a direct add to the PC (for Thumb2).
5497 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04005498 }
5499}
5500
Andreas Gampe85b62f22015-09-09 13:15:38 -07005501void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
5502 if (!trg.IsValid()) {
5503 DCHECK(type == Primitive::kPrimVoid);
5504 return;
5505 }
5506
5507 DCHECK_NE(type, Primitive::kPrimVoid);
5508
5509 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
5510 if (return_loc.Equals(trg)) {
5511 return;
5512 }
5513
5514 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
5515 // with the last branch.
5516 if (type == Primitive::kPrimLong) {
5517 HParallelMove parallel_move(GetGraph()->GetArena());
5518 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
5519 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
5520 GetMoveResolver()->EmitNativeCode(&parallel_move);
5521 } else if (type == Primitive::kPrimDouble) {
5522 HParallelMove parallel_move(GetGraph()->GetArena());
5523 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
5524 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
5525 GetMoveResolver()->EmitNativeCode(&parallel_move);
5526 } else {
5527 // Let the parallel move resolver take care of all of this.
5528 HParallelMove parallel_move(GetGraph()->GetArena());
5529 parallel_move.AddMove(return_loc, trg, type, nullptr);
5530 GetMoveResolver()->EmitNativeCode(&parallel_move);
5531 }
5532}
5533
Roland Levillain4d027112015-07-01 15:41:14 +01005534#undef __
5535#undef QUICK_ENTRY_POINT
5536
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00005537} // namespace arm
5538} // namespace art