blob: 655bbb8a8e2a412dc75f7bd71703f0154272a897 [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 Geoffray56b9ee62014-10-09 11:47:51 +01003194 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003195 locations->SetInAt(0, 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) {
3200 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003201 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003202 // Note: if heap poisoning is enabled, the entry point takes cares
3203 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003204 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003205 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003206 instruction->GetDexPc(),
3207 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003208}
3209
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003210void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
3211 LocationSummary* locations =
3212 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3213 InvokeRuntimeCallingConvention calling_convention;
3214 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003215 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003216 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003217 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003218}
3219
3220void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
3221 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003222 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Roland Levillain4d027112015-07-01 15:41:14 +01003223 // Note: if heap poisoning is enabled, the entry point takes cares
3224 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003225 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00003226 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003227 instruction->GetDexPc(),
3228 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003229}
3230
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003231void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003232 LocationSummary* locations =
3233 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003234 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3235 if (location.IsStackSlot()) {
3236 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3237 } else if (location.IsDoubleStackSlot()) {
3238 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003239 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003240 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003241}
3242
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003243void InstructionCodeGeneratorARM::VisitParameterValue(
3244 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003245 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003246}
3247
3248void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
3249 LocationSummary* locations =
3250 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3251 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3252}
3253
3254void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
3255 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003256}
3257
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003258void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003259 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003260 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003261 locations->SetInAt(0, Location::RequiresRegister());
3262 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003263}
3264
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003265void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
3266 LocationSummary* locations = not_->GetLocations();
3267 Location out = locations->Out();
3268 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003269 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003270 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003271 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003272 break;
3273
3274 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003275 __ mvn(out.AsRegisterPairLow<Register>(),
3276 ShifterOperand(in.AsRegisterPairLow<Register>()));
3277 __ mvn(out.AsRegisterPairHigh<Register>(),
3278 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003279 break;
3280
3281 default:
3282 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3283 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003284}
3285
David Brazdil66d126e2015-04-03 16:02:44 +01003286void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
3287 LocationSummary* locations =
3288 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3289 locations->SetInAt(0, Location::RequiresRegister());
3290 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3291}
3292
3293void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003294 LocationSummary* locations = bool_not->GetLocations();
3295 Location out = locations->Out();
3296 Location in = locations->InAt(0);
3297 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
3298}
3299
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003300void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003301 LocationSummary* locations =
3302 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003303 switch (compare->InputAt(0)->GetType()) {
3304 case Primitive::kPrimLong: {
3305 locations->SetInAt(0, Location::RequiresRegister());
3306 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003307 // Output overlaps because it is written before doing the low comparison.
3308 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00003309 break;
3310 }
3311 case Primitive::kPrimFloat:
3312 case Primitive::kPrimDouble: {
3313 locations->SetInAt(0, Location::RequiresFpuRegister());
3314 locations->SetInAt(1, Location::RequiresFpuRegister());
3315 locations->SetOut(Location::RequiresRegister());
3316 break;
3317 }
3318 default:
3319 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3320 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003321}
3322
3323void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003324 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003325 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003326 Location left = locations->InAt(0);
3327 Location right = locations->InAt(1);
3328
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003329 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00003330 Primitive::Type type = compare->InputAt(0)->GetType();
3331 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003332 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003333 __ cmp(left.AsRegisterPairHigh<Register>(),
3334 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003335 __ b(&less, LT);
3336 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003337 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00003338 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003339 __ cmp(left.AsRegisterPairLow<Register>(),
3340 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00003341 break;
3342 }
3343 case Primitive::kPrimFloat:
3344 case Primitive::kPrimDouble: {
3345 __ LoadImmediate(out, 0);
3346 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003347 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003348 } else {
3349 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
3350 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
3351 }
3352 __ vmstat(); // transfer FP status register to ARM APSR.
3353 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003354 break;
3355 }
3356 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003357 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003358 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003359 __ b(&done, EQ);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003360 __ b(&less, LO); // LO is for both: unsigned compare for longs and 'less than' for floats.
Calin Juravleddb7df22014-11-25 20:56:51 +00003361
3362 __ Bind(&greater);
3363 __ LoadImmediate(out, 1);
3364 __ b(&done);
3365
3366 __ Bind(&less);
3367 __ LoadImmediate(out, -1);
3368
3369 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003370}
3371
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003372void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003373 LocationSummary* locations =
3374 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003375 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3376 locations->SetInAt(i, Location::Any());
3377 }
3378 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003379}
3380
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003381void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003382 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003383}
3384
Calin Juravle52c48962014-12-16 17:02:57 +00003385void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
3386 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07003387 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00003388 switch (kind) {
3389 case MemBarrierKind::kAnyStore:
3390 case MemBarrierKind::kLoadAny:
3391 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003392 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00003393 break;
3394 }
3395 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07003396 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00003397 break;
3398 }
3399 default:
3400 LOG(FATAL) << "Unexpected memory barrier " << kind;
3401 }
Kenny Root1d8199d2015-06-02 11:01:10 -07003402 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00003403}
3404
3405void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
3406 uint32_t offset,
3407 Register out_lo,
3408 Register out_hi) {
3409 if (offset != 0) {
3410 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003411 __ add(IP, addr, ShifterOperand(out_lo));
3412 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003413 }
3414 __ ldrexd(out_lo, out_hi, addr);
3415}
3416
3417void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
3418 uint32_t offset,
3419 Register value_lo,
3420 Register value_hi,
3421 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00003422 Register temp2,
3423 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00003424 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00003425 if (offset != 0) {
3426 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00003427 __ add(IP, addr, ShifterOperand(temp1));
3428 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00003429 }
3430 __ Bind(&fail);
3431 // We need a load followed by store. (The address used in a STREX instruction must
3432 // be the same as the address in the most recently executed LDREX instruction.)
3433 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00003434 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003435 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003436 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00003437}
3438
3439void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3440 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3441
Nicolas Geoffray39468442014-09-02 15:17:15 +01003442 LocationSummary* locations =
3443 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003444 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003445
Calin Juravle52c48962014-12-16 17:02:57 +00003446 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003447 if (Primitive::IsFloatingPointType(field_type)) {
3448 locations->SetInAt(1, Location::RequiresFpuRegister());
3449 } else {
3450 locations->SetInAt(1, Location::RequiresRegister());
3451 }
3452
Calin Juravle52c48962014-12-16 17:02:57 +00003453 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00003454 bool generate_volatile = field_info.IsVolatile()
3455 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003456 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01003457 bool needs_write_barrier =
3458 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003459 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00003460 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01003461 if (needs_write_barrier) {
3462 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003463 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00003464 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00003465 // Arm encoding have some additional constraints for ldrexd/strexd:
3466 // - registers need to be consecutive
3467 // - the first register should be even but not R14.
3468 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3469 // enable Arm encoding.
3470 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3471
3472 locations->AddTemp(Location::RequiresRegister());
3473 locations->AddTemp(Location::RequiresRegister());
3474 if (field_type == Primitive::kPrimDouble) {
3475 // For doubles we need two more registers to copy the value.
3476 locations->AddTemp(Location::RegisterLocation(R2));
3477 locations->AddTemp(Location::RegisterLocation(R3));
3478 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003479 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003480}
3481
Calin Juravle52c48962014-12-16 17:02:57 +00003482void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003483 const FieldInfo& field_info,
3484 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003485 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3486
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003487 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003488 Register base = locations->InAt(0).AsRegister<Register>();
3489 Location value = locations->InAt(1);
3490
3491 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003492 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003493 Primitive::Type field_type = field_info.GetFieldType();
3494 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003495 bool needs_write_barrier =
3496 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003497
3498 if (is_volatile) {
3499 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3500 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003501
3502 switch (field_type) {
3503 case Primitive::kPrimBoolean:
3504 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003505 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003506 break;
3507 }
3508
3509 case Primitive::kPrimShort:
3510 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003511 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003512 break;
3513 }
3514
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003515 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003516 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003517 if (kPoisonHeapReferences && needs_write_barrier) {
3518 // Note that in the case where `value` is a null reference,
3519 // we do not enter this block, as a null reference does not
3520 // need poisoning.
3521 DCHECK_EQ(field_type, Primitive::kPrimNot);
3522 Register temp = locations->GetTemp(0).AsRegister<Register>();
3523 __ Mov(temp, value.AsRegister<Register>());
3524 __ PoisonHeapReference(temp);
3525 __ StoreToOffset(kStoreWord, temp, base, offset);
3526 } else {
3527 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
3528 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003529 break;
3530 }
3531
3532 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003533 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003534 GenerateWideAtomicStore(base, offset,
3535 value.AsRegisterPairLow<Register>(),
3536 value.AsRegisterPairHigh<Register>(),
3537 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003538 locations->GetTemp(1).AsRegister<Register>(),
3539 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003540 } else {
3541 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003542 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003543 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003544 break;
3545 }
3546
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003547 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003548 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003549 break;
3550 }
3551
3552 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003553 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003554 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003555 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3556 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3557
3558 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3559
3560 GenerateWideAtomicStore(base, offset,
3561 value_reg_lo,
3562 value_reg_hi,
3563 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003564 locations->GetTemp(3).AsRegister<Register>(),
3565 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003566 } else {
3567 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003568 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003569 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003570 break;
3571 }
3572
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003573 case Primitive::kPrimVoid:
3574 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003575 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003576 }
Calin Juravle52c48962014-12-16 17:02:57 +00003577
Calin Juravle77520bc2015-01-12 18:45:46 +00003578 // Longs and doubles are handled in the switch.
3579 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3580 codegen_->MaybeRecordImplicitNullCheck(instruction);
3581 }
3582
3583 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3584 Register temp = locations->GetTemp(0).AsRegister<Register>();
3585 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003586 codegen_->MarkGCCard(
3587 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003588 }
3589
Calin Juravle52c48962014-12-16 17:02:57 +00003590 if (is_volatile) {
3591 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3592 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003593}
3594
Calin Juravle52c48962014-12-16 17:02:57 +00003595void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3596 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003597 LocationSummary* locations =
3598 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003599 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003600
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003601 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003602 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003603 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003604 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003605
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003606 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3607 locations->SetOut(Location::RequiresFpuRegister());
3608 } else {
3609 locations->SetOut(Location::RequiresRegister(),
3610 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3611 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003612 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00003613 // Arm encoding have some additional constraints for ldrexd/strexd:
3614 // - registers need to be consecutive
3615 // - the first register should be even but not R14.
3616 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3617 // enable Arm encoding.
3618 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3619 locations->AddTemp(Location::RequiresRegister());
3620 locations->AddTemp(Location::RequiresRegister());
3621 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003622}
3623
Vladimir Markod2b4ca22015-09-14 15:13:26 +01003624Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
3625 Opcode opcode) {
3626 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
3627 if (constant->IsConstant() &&
3628 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
3629 return Location::ConstantLocation(constant->AsConstant());
3630 }
3631 return Location::RequiresRegister();
3632}
3633
3634bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
3635 Opcode opcode) {
3636 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
3637 if (Primitive::Is64BitType(input_cst->GetType())) {
3638 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
3639 CanEncodeConstantAsImmediate(High32Bits(value), opcode);
3640 } else {
3641 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
3642 }
3643}
3644
3645bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
3646 ShifterOperand so;
3647 ArmAssembler* assembler = codegen_->GetAssembler();
3648 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
3649 return true;
3650 }
3651 Opcode neg_opcode = kNoOperand;
3652 switch (opcode) {
3653 case AND:
3654 neg_opcode = BIC;
3655 break;
3656 case ORR:
3657 neg_opcode = ORN;
3658 break;
3659 default:
3660 return false;
3661 }
3662 return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
3663}
3664
Calin Juravle52c48962014-12-16 17:02:57 +00003665void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
3666 const FieldInfo& field_info) {
3667 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003668
Calin Juravle52c48962014-12-16 17:02:57 +00003669 LocationSummary* locations = instruction->GetLocations();
3670 Register base = locations->InAt(0).AsRegister<Register>();
3671 Location out = locations->Out();
3672 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003673 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003674 Primitive::Type field_type = field_info.GetFieldType();
3675 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3676
3677 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003678 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003679 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003680 break;
3681 }
3682
3683 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003684 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003685 break;
3686 }
3687
3688 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003689 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003690 break;
3691 }
3692
3693 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003694 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003695 break;
3696 }
3697
3698 case Primitive::kPrimInt:
3699 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003700 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003701 break;
3702 }
3703
3704 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003705 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003706 GenerateWideAtomicLoad(base, offset,
3707 out.AsRegisterPairLow<Register>(),
3708 out.AsRegisterPairHigh<Register>());
3709 } else {
3710 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3711 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003712 break;
3713 }
3714
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003715 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003716 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003717 break;
3718 }
3719
3720 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003721 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003722 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003723 Register lo = locations->GetTemp(0).AsRegister<Register>();
3724 Register hi = locations->GetTemp(1).AsRegister<Register>();
3725 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003726 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003727 __ vmovdrr(out_reg, lo, hi);
3728 } else {
3729 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003730 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003731 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003732 break;
3733 }
3734
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003735 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003736 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003737 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003738 }
Calin Juravle52c48962014-12-16 17:02:57 +00003739
Calin Juravle77520bc2015-01-12 18:45:46 +00003740 // Doubles are handled in the switch.
3741 if (field_type != Primitive::kPrimDouble) {
3742 codegen_->MaybeRecordImplicitNullCheck(instruction);
3743 }
3744
Calin Juravle52c48962014-12-16 17:02:57 +00003745 if (is_volatile) {
3746 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3747 }
Roland Levillain4d027112015-07-01 15:41:14 +01003748
3749 if (field_type == Primitive::kPrimNot) {
3750 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3751 }
Calin Juravle52c48962014-12-16 17:02:57 +00003752}
3753
3754void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3755 HandleFieldSet(instruction, instruction->GetFieldInfo());
3756}
3757
3758void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003759 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003760}
3761
3762void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3763 HandleFieldGet(instruction, instruction->GetFieldInfo());
3764}
3765
3766void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3767 HandleFieldGet(instruction, instruction->GetFieldInfo());
3768}
3769
3770void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3771 HandleFieldGet(instruction, instruction->GetFieldInfo());
3772}
3773
3774void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3775 HandleFieldGet(instruction, instruction->GetFieldInfo());
3776}
3777
3778void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3779 HandleFieldSet(instruction, instruction->GetFieldInfo());
3780}
3781
3782void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003783 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003784}
3785
Calin Juravlee460d1d2015-09-29 04:52:17 +01003786void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
3787 HUnresolvedInstanceFieldGet* instruction) {
3788 FieldAccessCallingConventionARM calling_convention;
3789 codegen_->CreateUnresolvedFieldLocationSummary(
3790 instruction, instruction->GetFieldType(), calling_convention);
3791}
3792
3793void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
3794 HUnresolvedInstanceFieldGet* instruction) {
3795 FieldAccessCallingConventionARM calling_convention;
3796 codegen_->GenerateUnresolvedFieldAccess(instruction,
3797 instruction->GetFieldType(),
3798 instruction->GetFieldIndex(),
3799 instruction->GetDexPc(),
3800 calling_convention);
3801}
3802
3803void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
3804 HUnresolvedInstanceFieldSet* instruction) {
3805 FieldAccessCallingConventionARM calling_convention;
3806 codegen_->CreateUnresolvedFieldLocationSummary(
3807 instruction, instruction->GetFieldType(), calling_convention);
3808}
3809
3810void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
3811 HUnresolvedInstanceFieldSet* instruction) {
3812 FieldAccessCallingConventionARM calling_convention;
3813 codegen_->GenerateUnresolvedFieldAccess(instruction,
3814 instruction->GetFieldType(),
3815 instruction->GetFieldIndex(),
3816 instruction->GetDexPc(),
3817 calling_convention);
3818}
3819
3820void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
3821 HUnresolvedStaticFieldGet* instruction) {
3822 FieldAccessCallingConventionARM calling_convention;
3823 codegen_->CreateUnresolvedFieldLocationSummary(
3824 instruction, instruction->GetFieldType(), calling_convention);
3825}
3826
3827void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
3828 HUnresolvedStaticFieldGet* instruction) {
3829 FieldAccessCallingConventionARM calling_convention;
3830 codegen_->GenerateUnresolvedFieldAccess(instruction,
3831 instruction->GetFieldType(),
3832 instruction->GetFieldIndex(),
3833 instruction->GetDexPc(),
3834 calling_convention);
3835}
3836
3837void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
3838 HUnresolvedStaticFieldSet* instruction) {
3839 FieldAccessCallingConventionARM calling_convention;
3840 codegen_->CreateUnresolvedFieldLocationSummary(
3841 instruction, instruction->GetFieldType(), calling_convention);
3842}
3843
3844void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
3845 HUnresolvedStaticFieldSet* instruction) {
3846 FieldAccessCallingConventionARM calling_convention;
3847 codegen_->GenerateUnresolvedFieldAccess(instruction,
3848 instruction->GetFieldType(),
3849 instruction->GetFieldIndex(),
3850 instruction->GetDexPc(),
3851 calling_convention);
3852}
3853
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003854void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003855 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3856 ? LocationSummary::kCallOnSlowPath
3857 : LocationSummary::kNoCall;
3858 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravle77520bc2015-01-12 18:45:46 +00003859 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003860 if (instruction->HasUses()) {
3861 locations->SetOut(Location::SameAsFirstInput());
3862 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003863}
3864
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003865void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003866 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3867 return;
3868 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003869 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003870
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003871 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3872 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3873}
3874
3875void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003876 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003877 codegen_->AddSlowPath(slow_path);
3878
3879 LocationSummary* locations = instruction->GetLocations();
3880 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003881
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01003882 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003883}
3884
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003885void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003886 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003887 GenerateImplicitNullCheck(instruction);
3888 } else {
3889 GenerateExplicitNullCheck(instruction);
3890 }
3891}
3892
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003893void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003894 LocationSummary* locations =
3895 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003896 locations->SetInAt(0, Location::RequiresRegister());
3897 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003898 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3899 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3900 } else {
3901 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3902 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003903}
3904
3905void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3906 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003907 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003908 Location index = locations->InAt(1);
Roland Levillain4d027112015-07-01 15:41:14 +01003909 Primitive::Type type = instruction->GetType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003910
Roland Levillain4d027112015-07-01 15:41:14 +01003911 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003912 case Primitive::kPrimBoolean: {
3913 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003914 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003915 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003916 size_t offset =
3917 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003918 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3919 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003920 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003921 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3922 }
3923 break;
3924 }
3925
3926 case Primitive::kPrimByte: {
3927 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003928 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003929 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003930 size_t offset =
3931 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003932 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3933 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003934 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003935 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3936 }
3937 break;
3938 }
3939
3940 case Primitive::kPrimShort: {
3941 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003942 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003943 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003944 size_t offset =
3945 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003946 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3947 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003948 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003949 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3950 }
3951 break;
3952 }
3953
3954 case Primitive::kPrimChar: {
3955 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003956 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003957 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003958 size_t offset =
3959 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003960 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3961 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003962 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003963 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3964 }
3965 break;
3966 }
3967
3968 case Primitive::kPrimInt:
3969 case Primitive::kPrimNot: {
Roland Levillain33d69032015-06-18 18:20:59 +01003970 static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
3971 "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003972 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003973 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003974 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003975 size_t offset =
3976 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003977 __ LoadFromOffset(kLoadWord, out, obj, offset);
3978 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003979 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003980 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3981 }
3982 break;
3983 }
3984
3985 case Primitive::kPrimLong: {
3986 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003987 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003988 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003989 size_t offset =
3990 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003991 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003992 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003993 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003994 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003995 }
3996 break;
3997 }
3998
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003999 case Primitive::kPrimFloat: {
4000 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4001 Location out = locations->Out();
4002 DCHECK(out.IsFpuRegister());
4003 if (index.IsConstant()) {
4004 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4005 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
4006 } else {
4007 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4008 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
4009 }
4010 break;
4011 }
4012
4013 case Primitive::kPrimDouble: {
4014 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4015 Location out = locations->Out();
4016 DCHECK(out.IsFpuRegisterPair());
4017 if (index.IsConstant()) {
4018 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4019 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
4020 } else {
4021 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
4022 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4023 }
4024 break;
4025 }
4026
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004027 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01004028 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004029 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004030 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004031 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01004032
4033 if (type == Primitive::kPrimNot) {
4034 Register out = locations->Out().AsRegister<Register>();
4035 __ MaybeUnpoisonHeapReference(out);
4036 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004037}
4038
4039void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004040 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004041
4042 bool needs_write_barrier =
4043 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004044 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004045
Nicolas Geoffray39468442014-09-02 15:17:15 +01004046 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004047 instruction,
4048 may_need_runtime_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
4049 locations->SetInAt(0, Location::RequiresRegister());
4050 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4051 if (Primitive::IsFloatingPointType(value_type)) {
4052 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004053 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004054 locations->SetInAt(2, Location::RequiresRegister());
4055 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004056
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004057 if (needs_write_barrier) {
4058 // Temporary registers for the write barrier.
4059 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
4060 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004061 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004062}
4063
4064void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
4065 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004066 Register array = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004067 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004068 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004069 bool may_need_runtime_call = locations->CanCall();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004070 bool needs_write_barrier =
4071 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004072
4073 switch (value_type) {
4074 case Primitive::kPrimBoolean:
4075 case Primitive::kPrimByte: {
4076 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004077 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004078 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004079 size_t offset =
4080 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004081 __ StoreToOffset(kStoreByte, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004082 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004083 __ add(IP, array, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004084 __ StoreToOffset(kStoreByte, value, IP, data_offset);
4085 }
4086 break;
4087 }
4088
4089 case Primitive::kPrimShort:
4090 case Primitive::kPrimChar: {
4091 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004092 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004093 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004094 size_t offset =
4095 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004096 __ StoreToOffset(kStoreHalfword, value, array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004097 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004098 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004099 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
4100 }
4101 break;
4102 }
4103
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004104 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004105 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4106 Register value = locations->InAt(2).AsRegister<Register>();
4107 Register source = value;
4108
4109 if (instruction->InputAt(2)->IsNullConstant()) {
4110 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004111 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004112 size_t offset =
4113 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004114 __ StoreToOffset(kStoreWord, source, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004115 } else {
4116 DCHECK(index.IsRegister()) << index;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004117 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillain4d027112015-07-01 15:41:14 +01004118 __ StoreToOffset(kStoreWord, source, IP, data_offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004119 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004120 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004121 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004122
4123 DCHECK(needs_write_barrier);
4124 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4125 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4126 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4127 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4128 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4129 Label done;
4130 SlowPathCode* slow_path = nullptr;
4131
4132 if (may_need_runtime_call) {
4133 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
4134 codegen_->AddSlowPath(slow_path);
4135 if (instruction->GetValueCanBeNull()) {
4136 Label non_zero;
4137 __ CompareAndBranchIfNonZero(value, &non_zero);
4138 if (index.IsConstant()) {
4139 size_t offset =
4140 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4141 __ StoreToOffset(kStoreWord, value, array, offset);
4142 } else {
4143 DCHECK(index.IsRegister()) << index;
4144 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4145 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4146 }
4147 codegen_->MaybeRecordImplicitNullCheck(instruction);
4148 __ b(&done);
4149 __ Bind(&non_zero);
4150 }
4151
4152 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
4153 codegen_->MaybeRecordImplicitNullCheck(instruction);
4154 __ MaybeUnpoisonHeapReference(temp1);
4155 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
4156 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
4157 // No need to poison/unpoison, we're comparing two poisoined references.
4158 __ cmp(temp1, ShifterOperand(temp2));
4159 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4160 Label do_put;
4161 __ b(&do_put, EQ);
4162 __ MaybeUnpoisonHeapReference(temp1);
4163 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
4164 // No need to poison/unpoison, we're comparing against null.
4165 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
4166 __ Bind(&do_put);
4167 } else {
4168 __ b(slow_path->GetEntryLabel(), NE);
4169 }
4170 }
4171
4172 if (kPoisonHeapReferences) {
4173 // Note that in the case where `value` is a null reference,
4174 // we do not enter this block, as a null reference does not
4175 // need poisoning.
4176 DCHECK_EQ(value_type, Primitive::kPrimNot);
4177 __ Mov(temp1, value);
4178 __ PoisonHeapReference(temp1);
4179 source = temp1;
4180 }
4181
4182 if (index.IsConstant()) {
4183 size_t offset =
4184 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4185 __ StoreToOffset(kStoreWord, source, array, offset);
4186 } else {
4187 DCHECK(index.IsRegister()) << index;
4188 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4189 __ StoreToOffset(kStoreWord, source, IP, data_offset);
4190 }
4191
4192 if (!may_need_runtime_call) {
4193 codegen_->MaybeRecordImplicitNullCheck(instruction);
4194 }
4195
4196 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
4197
4198 if (done.IsLinked()) {
4199 __ Bind(&done);
4200 }
4201
4202 if (slow_path != nullptr) {
4203 __ Bind(slow_path->GetExitLabel());
4204 }
4205
4206 break;
4207 }
4208
4209 case Primitive::kPrimInt: {
4210 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4211 Register value = locations->InAt(2).AsRegister<Register>();
4212 if (index.IsConstant()) {
4213 size_t offset =
4214 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4215 __ StoreToOffset(kStoreWord, value, array, offset);
4216 } else {
4217 DCHECK(index.IsRegister()) << index;
4218 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
4219 __ StoreToOffset(kStoreWord, value, IP, data_offset);
4220 }
4221
4222 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004223 break;
4224 }
4225
4226 case Primitive::kPrimLong: {
4227 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004228 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004229 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004230 size_t offset =
4231 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004232 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004233 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004234 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004235 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004236 }
4237 break;
4238 }
4239
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004240 case Primitive::kPrimFloat: {
4241 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4242 Location value = locations->InAt(2);
4243 DCHECK(value.IsFpuRegister());
4244 if (index.IsConstant()) {
4245 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004246 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004247 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004248 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004249 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
4250 }
4251 break;
4252 }
4253
4254 case Primitive::kPrimDouble: {
4255 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4256 Location value = locations->InAt(2);
4257 DCHECK(value.IsFpuRegisterPair());
4258 if (index.IsConstant()) {
4259 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004260 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004261 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004262 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004263 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
4264 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004265
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004266 break;
4267 }
4268
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004269 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004270 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004271 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004272 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004273
4274 // Ints and objects are handled in the switch.
4275 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
4276 codegen_->MaybeRecordImplicitNullCheck(instruction);
4277 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004278}
4279
4280void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004281 LocationSummary* locations =
4282 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004283 locations->SetInAt(0, Location::RequiresRegister());
4284 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004285}
4286
4287void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
4288 LocationSummary* locations = instruction->GetLocations();
4289 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004290 Register obj = locations->InAt(0).AsRegister<Register>();
4291 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004292 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00004293 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004294}
4295
4296void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004297 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4298 ? LocationSummary::kCallOnSlowPath
4299 : LocationSummary::kNoCall;
4300 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004301 locations->SetInAt(0, Location::RequiresRegister());
4302 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004303 if (instruction->HasUses()) {
4304 locations->SetOut(Location::SameAsFirstInput());
4305 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004306}
4307
4308void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
4309 LocationSummary* locations = instruction->GetLocations();
Andreas Gampe85b62f22015-09-09 13:15:38 -07004310 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004311 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004312 codegen_->AddSlowPath(slow_path);
4313
Roland Levillain271ab9c2014-11-27 15:23:57 +00004314 Register index = locations->InAt(0).AsRegister<Register>();
4315 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004316
4317 __ cmp(index, ShifterOperand(length));
Roland Levillain4fa13f62015-07-06 18:11:54 +01004318 __ b(slow_path->GetEntryLabel(), HS);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004319}
4320
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004321void CodeGeneratorARM::MarkGCCard(Register temp,
4322 Register card,
4323 Register object,
4324 Register value,
4325 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004326 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004327 if (can_be_null) {
4328 __ CompareAndBranchIfZero(value, &is_null);
4329 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004330 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
4331 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
4332 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004333 if (can_be_null) {
4334 __ Bind(&is_null);
4335 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004336}
4337
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004338void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
4339 temp->SetLocations(nullptr);
4340}
4341
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004342void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004343 // Nothing to do, this is driven by the code generator.
4344}
4345
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01004346void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004347 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004348}
4349
4350void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004351 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4352}
4353
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004354void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
4355 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4356}
4357
4358void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004359 HBasicBlock* block = instruction->GetBlock();
4360 if (block->GetLoopInformation() != nullptr) {
4361 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4362 // The back edge will generate the suspend check.
4363 return;
4364 }
4365 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4366 // The goto will generate the suspend check.
4367 return;
4368 }
4369 GenerateSuspendCheck(instruction, nullptr);
4370}
4371
4372void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
4373 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004374 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004375 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
4376 if (slow_path == nullptr) {
4377 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
4378 instruction->SetSlowPath(slow_path);
4379 codegen_->AddSlowPath(slow_path);
4380 if (successor != nullptr) {
4381 DCHECK(successor->IsLoopHeader());
4382 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4383 }
4384 } else {
4385 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4386 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004387
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00004388 __ LoadFromOffset(
4389 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004390 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004391 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004392 __ Bind(slow_path->GetReturnLabel());
4393 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004394 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004395 __ b(slow_path->GetEntryLabel());
4396 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004397}
4398
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004399ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
4400 return codegen_->GetAssembler();
4401}
4402
4403void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004404 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004405 Location source = move->GetSource();
4406 Location destination = move->GetDestination();
4407
4408 if (source.IsRegister()) {
4409 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004410 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004411 } else {
4412 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004413 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004414 SP, destination.GetStackIndex());
4415 }
4416 } else if (source.IsStackSlot()) {
4417 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004418 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004419 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004420 } else if (destination.IsFpuRegister()) {
4421 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004422 } else {
4423 DCHECK(destination.IsStackSlot());
4424 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
4425 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4426 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004427 } else if (source.IsFpuRegister()) {
4428 if (destination.IsFpuRegister()) {
4429 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004430 } else {
4431 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004432 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
4433 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004434 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004435 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004436 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
4437 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004438 } else if (destination.IsRegisterPair()) {
4439 DCHECK(ExpectedPairLayout(destination));
4440 __ LoadFromOffset(
4441 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
4442 } else {
4443 DCHECK(destination.IsFpuRegisterPair()) << destination;
4444 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4445 SP,
4446 source.GetStackIndex());
4447 }
4448 } else if (source.IsRegisterPair()) {
4449 if (destination.IsRegisterPair()) {
4450 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
4451 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
4452 } else {
4453 DCHECK(destination.IsDoubleStackSlot()) << destination;
4454 DCHECK(ExpectedPairLayout(source));
4455 __ StoreToOffset(
4456 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
4457 }
4458 } else if (source.IsFpuRegisterPair()) {
4459 if (destination.IsFpuRegisterPair()) {
4460 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
4461 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
4462 } else {
4463 DCHECK(destination.IsDoubleStackSlot()) << destination;
4464 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
4465 SP,
4466 destination.GetStackIndex());
4467 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004468 } else {
4469 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004470 HConstant* constant = source.GetConstant();
4471 if (constant->IsIntConstant() || constant->IsNullConstant()) {
4472 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004473 if (destination.IsRegister()) {
4474 __ LoadImmediate(destination.AsRegister<Register>(), value);
4475 } else {
4476 DCHECK(destination.IsStackSlot());
4477 __ LoadImmediate(IP, value);
4478 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4479 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004480 } else if (constant->IsLongConstant()) {
4481 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004482 if (destination.IsRegisterPair()) {
4483 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
4484 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004485 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004486 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004487 __ LoadImmediate(IP, Low32Bits(value));
4488 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4489 __ LoadImmediate(IP, High32Bits(value));
4490 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4491 }
4492 } else if (constant->IsDoubleConstant()) {
4493 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004494 if (destination.IsFpuRegisterPair()) {
4495 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004496 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004497 DCHECK(destination.IsDoubleStackSlot()) << destination;
4498 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004499 __ LoadImmediate(IP, Low32Bits(int_value));
4500 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4501 __ LoadImmediate(IP, High32Bits(int_value));
4502 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
4503 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004504 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004505 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004506 float value = constant->AsFloatConstant()->GetValue();
4507 if (destination.IsFpuRegister()) {
4508 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
4509 } else {
4510 DCHECK(destination.IsStackSlot());
4511 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
4512 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
4513 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004514 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004515 }
4516}
4517
4518void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
4519 __ Mov(IP, reg);
4520 __ LoadFromOffset(kLoadWord, reg, SP, mem);
4521 __ StoreToOffset(kStoreWord, IP, SP, mem);
4522}
4523
4524void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
4525 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
4526 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
4527 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
4528 SP, mem1 + stack_offset);
4529 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
4530 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
4531 SP, mem2 + stack_offset);
4532 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
4533}
4534
4535void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004536 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004537 Location source = move->GetSource();
4538 Location destination = move->GetDestination();
4539
4540 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004541 DCHECK_NE(source.AsRegister<Register>(), IP);
4542 DCHECK_NE(destination.AsRegister<Register>(), IP);
4543 __ Mov(IP, source.AsRegister<Register>());
4544 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
4545 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004546 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004547 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004548 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004549 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004550 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4551 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004552 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004553 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004554 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004555 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004556 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004557 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004558 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004559 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004560 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
4561 destination.AsRegisterPairHigh<Register>(),
4562 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004563 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004564 Register low_reg = source.IsRegisterPair()
4565 ? source.AsRegisterPairLow<Register>()
4566 : destination.AsRegisterPairLow<Register>();
4567 int mem = source.IsRegisterPair()
4568 ? destination.GetStackIndex()
4569 : source.GetStackIndex();
4570 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004571 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004572 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004573 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004574 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004575 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
4576 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004577 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004578 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004579 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004580 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
4581 DRegister reg = source.IsFpuRegisterPair()
4582 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
4583 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
4584 int mem = source.IsFpuRegisterPair()
4585 ? destination.GetStackIndex()
4586 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004587 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004588 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00004589 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00004590 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
4591 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
4592 : destination.AsFpuRegister<SRegister>();
4593 int mem = source.IsFpuRegister()
4594 ? destination.GetStackIndex()
4595 : source.GetStackIndex();
4596
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004597 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00004598 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00004599 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004600 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004601 Exchange(source.GetStackIndex(), destination.GetStackIndex());
4602 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004603 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00004604 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004605 }
4606}
4607
4608void ParallelMoveResolverARM::SpillScratch(int reg) {
4609 __ Push(static_cast<Register>(reg));
4610}
4611
4612void ParallelMoveResolverARM::RestoreScratch(int reg) {
4613 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004614}
4615
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004616void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01004617 InvokeRuntimeCallingConvention calling_convention;
4618 CodeGenerator::CreateLoadClassLocationSummary(
4619 cls,
4620 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
4621 Location::RegisterLocation(R0));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004622}
4623
4624void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004625 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01004626 if (cls->NeedsAccessCheck()) {
4627 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
4628 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
4629 cls,
4630 cls->GetDexPc(),
4631 nullptr);
Calin Juravle580b6092015-10-06 17:35:58 +01004632 return;
4633 }
4634
4635 Register out = locations->Out().AsRegister<Register>();
4636 Register current_method = locations->InAt(0).AsRegister<Register>();
4637 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004638 DCHECK(!cls->CanCallRuntime());
4639 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004640 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004641 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004642 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004643 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004644 __ LoadFromOffset(kLoadWord,
4645 out,
4646 current_method,
Vladimir Marko05792b92015-08-03 11:56:49 +01004647 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004648 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004649 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004650
Andreas Gampe85b62f22015-09-09 13:15:38 -07004651 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004652 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4653 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004654 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004655 if (cls->MustGenerateClinitCheck()) {
4656 GenerateClassInitializationCheck(slow_path, out);
4657 } else {
4658 __ Bind(slow_path->GetExitLabel());
4659 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004660 }
4661}
4662
4663void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
4664 LocationSummary* locations =
4665 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4666 locations->SetInAt(0, Location::RequiresRegister());
4667 if (check->HasUses()) {
4668 locations->SetOut(Location::SameAsFirstInput());
4669 }
4670}
4671
4672void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004673 // We assume the class is not null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07004674 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004675 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004676 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004677 GenerateClassInitializationCheck(slow_path,
4678 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004679}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004680
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004681void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07004682 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004683 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
4684 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
4685 __ b(slow_path->GetEntryLabel(), LT);
4686 // Even if the initialized flag is set, we may be in a situation where caches are not synced
4687 // properly. Therefore, we do a memory fence.
4688 __ dmb(ISH);
4689 __ Bind(slow_path->GetExitLabel());
4690}
4691
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004692void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
4693 LocationSummary* locations =
4694 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004695 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004696 locations->SetOut(Location::RequiresRegister());
4697}
4698
4699void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004700 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004701 codegen_->AddSlowPath(slow_path);
4702
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004703 LocationSummary* locations = load->GetLocations();
4704 Register out = locations->Out().AsRegister<Register>();
4705 Register current_method = locations->InAt(0).AsRegister<Register>();
4706 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004707 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Mathieu Chartiereace4582014-11-24 18:29:54 -08004708 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004709 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
Vladimir Marko05792b92015-08-03 11:56:49 +01004710 // TODO: We will need a read barrier here.
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004711 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004712 __ Bind(slow_path->GetExitLabel());
4713}
4714
David Brazdilcb1c0552015-08-04 16:22:25 +01004715static int32_t GetExceptionTlsOffset() {
4716 return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
4717}
4718
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004719void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
4720 LocationSummary* locations =
4721 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4722 locations->SetOut(Location::RequiresRegister());
4723}
4724
4725void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004726 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01004727 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
4728}
4729
4730void LocationsBuilderARM::VisitClearException(HClearException* clear) {
4731 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4732}
4733
4734void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004735 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01004736 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004737}
4738
4739void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
4740 LocationSummary* locations =
4741 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4742 InvokeRuntimeCallingConvention calling_convention;
4743 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4744}
4745
4746void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
4747 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004748 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004749}
4750
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004751void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004752 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4753 switch (instruction->GetTypeCheckKind()) {
4754 case TypeCheckKind::kExactCheck:
4755 case TypeCheckKind::kAbstractClassCheck:
4756 case TypeCheckKind::kClassHierarchyCheck:
4757 case TypeCheckKind::kArrayObjectCheck:
4758 call_kind = LocationSummary::kNoCall;
4759 break;
Calin Juravle98893e12015-10-02 21:05:03 +01004760 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004761 case TypeCheckKind::kInterfaceCheck:
4762 call_kind = LocationSummary::kCall;
4763 break;
4764 case TypeCheckKind::kArrayCheck:
4765 call_kind = LocationSummary::kCallOnSlowPath;
4766 break;
4767 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004768 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004769 if (call_kind != LocationSummary::kCall) {
4770 locations->SetInAt(0, Location::RequiresRegister());
4771 locations->SetInAt(1, Location::RequiresRegister());
4772 // The out register is used as a temporary, so it overlaps with the inputs.
4773 // Note that TypeCheckSlowPathARM uses this register too.
4774 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4775 } else {
4776 InvokeRuntimeCallingConvention calling_convention;
4777 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4778 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4779 locations->SetOut(Location::RegisterLocation(R0));
4780 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004781}
4782
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004783void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004784 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004785 Register obj = locations->InAt(0).AsRegister<Register>();
4786 Register cls = locations->InAt(1).AsRegister<Register>();
4787 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004788 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004789 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4790 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4791 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004792 Label done, zero;
Andreas Gampe85b62f22015-09-09 13:15:38 -07004793 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004794
4795 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004796 // avoid null check if we know obj is not null.
4797 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00004798 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004799 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004800
Calin Juravle98893e12015-10-02 21:05:03 +01004801 // In case of an interface/unresolved check, we put the object class into the object register.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004802 // This is safe, as the register is caller-save, and the object must be in another
4803 // register if it survives the runtime call.
Calin Juravle98893e12015-10-02 21:05:03 +01004804 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
4805 (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004806 ? obj
4807 : out;
4808 __ LoadFromOffset(kLoadWord, target, obj, class_offset);
4809 __ MaybeUnpoisonHeapReference(target);
4810
4811 switch (instruction->GetTypeCheckKind()) {
4812 case TypeCheckKind::kExactCheck: {
4813 __ cmp(out, ShifterOperand(cls));
4814 // Classes must be equal for the instanceof to succeed.
4815 __ b(&zero, NE);
4816 __ LoadImmediate(out, 1);
4817 __ b(&done);
4818 break;
4819 }
4820 case TypeCheckKind::kAbstractClassCheck: {
4821 // If the class is abstract, we eagerly fetch the super class of the
4822 // object to avoid doing a comparison we know will fail.
4823 Label loop;
4824 __ Bind(&loop);
4825 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4826 __ MaybeUnpoisonHeapReference(out);
4827 // If `out` is null, we use it for the result, and jump to `done`.
4828 __ CompareAndBranchIfZero(out, &done);
4829 __ cmp(out, ShifterOperand(cls));
4830 __ b(&loop, NE);
4831 __ LoadImmediate(out, 1);
4832 if (zero.IsLinked()) {
4833 __ b(&done);
4834 }
4835 break;
4836 }
4837 case TypeCheckKind::kClassHierarchyCheck: {
4838 // Walk over the class hierarchy to find a match.
4839 Label loop, success;
4840 __ Bind(&loop);
4841 __ cmp(out, ShifterOperand(cls));
4842 __ b(&success, EQ);
4843 __ LoadFromOffset(kLoadWord, out, out, super_offset);
4844 __ MaybeUnpoisonHeapReference(out);
4845 __ CompareAndBranchIfNonZero(out, &loop);
4846 // If `out` is null, we use it for the result, and jump to `done`.
4847 __ b(&done);
4848 __ Bind(&success);
4849 __ LoadImmediate(out, 1);
4850 if (zero.IsLinked()) {
4851 __ b(&done);
4852 }
4853 break;
4854 }
4855 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004856 // Do an exact check.
4857 Label exact_check;
4858 __ cmp(out, ShifterOperand(cls));
4859 __ b(&exact_check, EQ);
4860 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004861 __ LoadFromOffset(kLoadWord, out, out, component_offset);
4862 __ MaybeUnpoisonHeapReference(out);
4863 // If `out` is null, we use it for the result, and jump to `done`.
4864 __ CompareAndBranchIfZero(out, &done);
4865 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
4866 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4867 __ CompareAndBranchIfNonZero(out, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01004868 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004869 __ LoadImmediate(out, 1);
4870 __ b(&done);
4871 break;
4872 }
4873 case TypeCheckKind::kArrayCheck: {
4874 __ cmp(out, ShifterOperand(cls));
4875 DCHECK(locations->OnlyCallsOnSlowPath());
4876 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4877 instruction, /* is_fatal */ false);
4878 codegen_->AddSlowPath(slow_path);
4879 __ b(slow_path->GetEntryLabel(), NE);
4880 __ LoadImmediate(out, 1);
4881 if (zero.IsLinked()) {
4882 __ b(&done);
4883 }
4884 break;
4885 }
Calin Juravle98893e12015-10-02 21:05:03 +01004886 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004887 case TypeCheckKind::kInterfaceCheck:
4888 default: {
4889 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
4890 instruction,
4891 instruction->GetDexPc(),
4892 nullptr);
4893 if (zero.IsLinked()) {
4894 __ b(&done);
4895 }
4896 break;
4897 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004898 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004899
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004900 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004901 __ Bind(&zero);
4902 __ LoadImmediate(out, 0);
4903 }
4904
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004905 if (done.IsLinked()) {
4906 __ Bind(&done);
4907 }
4908
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004909 if (slow_path != nullptr) {
4910 __ Bind(slow_path->GetExitLabel());
4911 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004912}
4913
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004914void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004915 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4916 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
4917
4918 switch (instruction->GetTypeCheckKind()) {
4919 case TypeCheckKind::kExactCheck:
4920 case TypeCheckKind::kAbstractClassCheck:
4921 case TypeCheckKind::kClassHierarchyCheck:
4922 case TypeCheckKind::kArrayObjectCheck:
4923 call_kind = throws_into_catch
4924 ? LocationSummary::kCallOnSlowPath
4925 : LocationSummary::kNoCall;
4926 break;
Calin Juravle98893e12015-10-02 21:05:03 +01004927 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004928 case TypeCheckKind::kInterfaceCheck:
4929 call_kind = LocationSummary::kCall;
4930 break;
4931 case TypeCheckKind::kArrayCheck:
4932 call_kind = LocationSummary::kCallOnSlowPath;
4933 break;
4934 }
4935
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004936 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004937 instruction, call_kind);
4938 if (call_kind != LocationSummary::kCall) {
4939 locations->SetInAt(0, Location::RequiresRegister());
4940 locations->SetInAt(1, Location::RequiresRegister());
4941 // Note that TypeCheckSlowPathARM uses this register too.
4942 locations->AddTemp(Location::RequiresRegister());
4943 } else {
4944 InvokeRuntimeCallingConvention calling_convention;
4945 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4946 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4947 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004948}
4949
4950void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
4951 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004952 Register obj = locations->InAt(0).AsRegister<Register>();
4953 Register cls = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004954 Register temp = locations->WillCall()
4955 ? Register(kNoRegister)
4956 : locations->GetTemp(0).AsRegister<Register>();
4957
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004958 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004959 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4960 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4961 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
4962 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004963
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004964 if (!locations->WillCall()) {
4965 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4966 instruction, !locations->CanCall());
4967 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray64acf302015-09-14 22:20:29 +01004968 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004969
4970 Label done;
4971 // Avoid null check if we know obj is not null.
4972 if (instruction->MustDoNullCheck()) {
4973 __ CompareAndBranchIfZero(obj, &done);
4974 }
4975
4976 if (locations->WillCall()) {
4977 __ LoadFromOffset(kLoadWord, obj, obj, class_offset);
4978 __ MaybeUnpoisonHeapReference(obj);
4979 } else {
4980 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
4981 __ MaybeUnpoisonHeapReference(temp);
4982 }
4983
4984 switch (instruction->GetTypeCheckKind()) {
4985 case TypeCheckKind::kExactCheck:
4986 case TypeCheckKind::kArrayCheck: {
4987 __ cmp(temp, ShifterOperand(cls));
4988 // Jump to slow path for throwing the exception or doing a
4989 // more involved array check.
4990 __ b(slow_path->GetEntryLabel(), NE);
4991 break;
4992 }
4993 case TypeCheckKind::kAbstractClassCheck: {
4994 // If the class is abstract, we eagerly fetch the super class of the
4995 // object to avoid doing a comparison we know will fail.
4996 Label loop;
4997 __ Bind(&loop);
4998 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
4999 __ MaybeUnpoisonHeapReference(temp);
5000 // Jump to the slow path to throw the exception.
5001 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
5002 __ cmp(temp, ShifterOperand(cls));
5003 __ b(&loop, NE);
5004 break;
5005 }
5006 case TypeCheckKind::kClassHierarchyCheck: {
5007 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005008 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005009 __ Bind(&loop);
5010 __ cmp(temp, ShifterOperand(cls));
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005011 __ b(&done, EQ);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005012 __ LoadFromOffset(kLoadWord, temp, temp, super_offset);
5013 __ MaybeUnpoisonHeapReference(temp);
5014 __ CompareAndBranchIfNonZero(temp, &loop);
5015 // Jump to the slow path to throw the exception.
5016 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005017 break;
5018 }
5019 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005020 // Do an exact check.
5021 __ cmp(temp, ShifterOperand(cls));
5022 __ b(&done, EQ);
5023 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005024 __ LoadFromOffset(kLoadWord, temp, temp, component_offset);
5025 __ MaybeUnpoisonHeapReference(temp);
5026 __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel());
5027 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
5028 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
5029 __ CompareAndBranchIfNonZero(temp, slow_path->GetEntryLabel());
5030 break;
5031 }
Calin Juravle98893e12015-10-02 21:05:03 +01005032 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005033 case TypeCheckKind::kInterfaceCheck:
5034 default:
5035 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
5036 instruction,
5037 instruction->GetDexPc(),
5038 nullptr);
5039 break;
5040 }
5041 __ Bind(&done);
5042
5043 if (slow_path != nullptr) {
5044 __ Bind(slow_path->GetExitLabel());
5045 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005046}
5047
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005048void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5049 LocationSummary* locations =
5050 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5051 InvokeRuntimeCallingConvention calling_convention;
5052 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5053}
5054
5055void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
5056 codegen_->InvokeRuntime(instruction->IsEnter()
5057 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
5058 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00005059 instruction->GetDexPc(),
5060 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005061}
5062
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005063void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
5064void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
5065void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005066
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005067void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005068 LocationSummary* locations =
5069 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5070 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5071 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005072 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005073 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005074 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005075 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005076}
5077
5078void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
5079 HandleBitwiseOperation(instruction);
5080}
5081
5082void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
5083 HandleBitwiseOperation(instruction);
5084}
5085
5086void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
5087 HandleBitwiseOperation(instruction);
5088}
5089
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005090void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
5091 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
5092 if (value == 0xffffffffu) {
5093 if (out != first) {
5094 __ mov(out, ShifterOperand(first));
5095 }
5096 return;
5097 }
5098 if (value == 0u) {
5099 __ mov(out, ShifterOperand(0));
5100 return;
5101 }
5102 ShifterOperand so;
5103 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
5104 __ and_(out, first, so);
5105 } else {
5106 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
5107 __ bic(out, first, ShifterOperand(~value));
5108 }
5109}
5110
5111void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
5112 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
5113 if (value == 0u) {
5114 if (out != first) {
5115 __ mov(out, ShifterOperand(first));
5116 }
5117 return;
5118 }
5119 if (value == 0xffffffffu) {
5120 __ mvn(out, ShifterOperand(0));
5121 return;
5122 }
5123 ShifterOperand so;
5124 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
5125 __ orr(out, first, so);
5126 } else {
5127 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
5128 __ orn(out, first, ShifterOperand(~value));
5129 }
5130}
5131
5132void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
5133 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
5134 if (value == 0u) {
5135 if (out != first) {
5136 __ mov(out, ShifterOperand(first));
5137 }
5138 return;
5139 }
5140 __ eor(out, first, ShifterOperand(value));
5141}
5142
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005143void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
5144 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005145 Location first = locations->InAt(0);
5146 Location second = locations->InAt(1);
5147 Location out = locations->Out();
5148
5149 if (second.IsConstant()) {
5150 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
5151 uint32_t value_low = Low32Bits(value);
5152 if (instruction->GetResultType() == Primitive::kPrimInt) {
5153 Register first_reg = first.AsRegister<Register>();
5154 Register out_reg = out.AsRegister<Register>();
5155 if (instruction->IsAnd()) {
5156 GenerateAndConst(out_reg, first_reg, value_low);
5157 } else if (instruction->IsOr()) {
5158 GenerateOrrConst(out_reg, first_reg, value_low);
5159 } else {
5160 DCHECK(instruction->IsXor());
5161 GenerateEorConst(out_reg, first_reg, value_low);
5162 }
5163 } else {
5164 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5165 uint32_t value_high = High32Bits(value);
5166 Register first_low = first.AsRegisterPairLow<Register>();
5167 Register first_high = first.AsRegisterPairHigh<Register>();
5168 Register out_low = out.AsRegisterPairLow<Register>();
5169 Register out_high = out.AsRegisterPairHigh<Register>();
5170 if (instruction->IsAnd()) {
5171 GenerateAndConst(out_low, first_low, value_low);
5172 GenerateAndConst(out_high, first_high, value_high);
5173 } else if (instruction->IsOr()) {
5174 GenerateOrrConst(out_low, first_low, value_low);
5175 GenerateOrrConst(out_high, first_high, value_high);
5176 } else {
5177 DCHECK(instruction->IsXor());
5178 GenerateEorConst(out_low, first_low, value_low);
5179 GenerateEorConst(out_high, first_high, value_high);
5180 }
5181 }
5182 return;
5183 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005184
5185 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005186 Register first_reg = first.AsRegister<Register>();
5187 ShifterOperand second_reg(second.AsRegister<Register>());
5188 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005189 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005190 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005191 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005192 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005193 } else {
5194 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005195 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005196 }
5197 } else {
5198 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005199 Register first_low = first.AsRegisterPairLow<Register>();
5200 Register first_high = first.AsRegisterPairHigh<Register>();
5201 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
5202 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
5203 Register out_low = out.AsRegisterPairLow<Register>();
5204 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005205 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005206 __ and_(out_low, first_low, second_low);
5207 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005208 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005209 __ orr(out_low, first_low, second_low);
5210 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005211 } else {
5212 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005213 __ eor(out_low, first_low, second_low);
5214 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005215 }
5216 }
5217}
5218
Vladimir Markodc151b22015-10-15 18:02:30 +01005219HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
5220 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
5221 MethodReference target_method) {
5222 if (desired_dispatch_info.method_load_kind ==
5223 HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative) {
5224 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
5225 return HInvokeStaticOrDirect::DispatchInfo {
5226 HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod,
5227 HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
5228 0u,
5229 0u
5230 };
5231 }
5232 if (desired_dispatch_info.code_ptr_location ==
5233 HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
5234 const DexFile& outer_dex_file = GetGraph()->GetDexFile();
5235 if (&outer_dex_file != target_method.dex_file) {
5236 // Calls across dex files are more likely to exceed the available BL range,
5237 // so use absolute patch with fixup if available and kCallArtMethod otherwise.
5238 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
5239 (desired_dispatch_info.method_load_kind ==
5240 HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup)
5241 ? HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup
5242 : HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
5243 return HInvokeStaticOrDirect::DispatchInfo {
5244 desired_dispatch_info.method_load_kind,
5245 code_ptr_location,
5246 desired_dispatch_info.method_load_data,
5247 0u
5248 };
5249 }
5250 }
5251 return desired_dispatch_info;
5252}
5253
Nicolas Geoffray38207af2015-06-01 15:46:22 +01005254void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00005255 // For better instruction scheduling we load the direct code pointer before the method pointer.
Vladimir Marko58155012015-08-19 12:49:41 +00005256 switch (invoke->GetCodePtrLocation()) {
Vladimir Marko58155012015-08-19 12:49:41 +00005257 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
5258 // LR = code address from literal pool with link-time patch.
5259 __ LoadLiteral(LR, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
Vladimir Marko58155012015-08-19 12:49:41 +00005260 break;
5261 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
5262 // LR = invoke->GetDirectCodePtr();
5263 __ LoadImmediate(LR, invoke->GetDirectCodePtr());
Vladimir Marko58155012015-08-19 12:49:41 +00005264 break;
5265 default:
5266 break;
5267 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005268
Vladimir Marko58155012015-08-19 12:49:41 +00005269 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
5270 switch (invoke->GetMethodLoadKind()) {
5271 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
5272 // temp = thread->string_init_entrypoint
5273 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
5274 break;
5275 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
5276 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
5277 break;
5278 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
5279 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
5280 break;
5281 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
5282 __ LoadLiteral(temp.AsRegister<Register>(),
5283 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
5284 break;
5285 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01005286 // TODO: Implement this type.
5287 // Currently filtered out by GetSupportedInvokeStaticOrDirectDispatch().
5288 LOG(FATAL) << "Unsupported";
5289 UNREACHABLE();
Vladimir Marko58155012015-08-19 12:49:41 +00005290 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
5291 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
5292 Register method_reg;
5293 Register reg = temp.AsRegister<Register>();
5294 if (current_method.IsRegister()) {
5295 method_reg = current_method.AsRegister<Register>();
5296 } else {
5297 DCHECK(invoke->GetLocations()->Intrinsified());
5298 DCHECK(!current_method.IsValid());
5299 method_reg = reg;
5300 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
5301 }
5302 // temp = current_method->dex_cache_resolved_methods_;
5303 __ LoadFromOffset(
Vladimir Marko05792b92015-08-03 11:56:49 +01005304 kLoadWord, reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset(
5305 kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00005306 // temp = temp[index_in_cache]
5307 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
5308 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
5309 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01005310 }
Vladimir Marko58155012015-08-19 12:49:41 +00005311 }
5312
5313 switch (invoke->GetCodePtrLocation()) {
5314 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
5315 __ bl(GetFrameEntryLabel());
5316 break;
5317 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01005318 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005319 __ BindTrackedLabel(&relative_call_patches_.back().label);
Vladimir Markodc151b22015-10-15 18:02:30 +01005320 // Arbitrarily branch to the BL itself, override at link time.
5321 __ bl(&relative_call_patches_.back().label);
5322 break;
Vladimir Marko58155012015-08-19 12:49:41 +00005323 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
5324 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
5325 // LR prepared above for better instruction scheduling.
Vladimir Marko58155012015-08-19 12:49:41 +00005326 // LR()
5327 __ blx(LR);
5328 break;
5329 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
5330 // LR = callee_method->entry_point_from_quick_compiled_code_
5331 __ LoadFromOffset(
5332 kLoadWord, LR, callee_method.AsRegister<Register>(),
5333 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize).Int32Value());
5334 // LR()
5335 __ blx(LR);
5336 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005337 }
5338
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08005339 DCHECK(!IsLeafMethod());
5340}
5341
Andreas Gampebfb5ba92015-09-01 15:45:02 +00005342void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
5343 Register temp = temp_location.AsRegister<Register>();
5344 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5345 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
5346 LocationSummary* locations = invoke->GetLocations();
5347 Location receiver = locations->InAt(0);
5348 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5349 // temp = object->GetClass();
5350 DCHECK(receiver.IsRegister());
5351 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
5352 MaybeRecordImplicitNullCheck(invoke);
5353 __ MaybeUnpoisonHeapReference(temp);
5354 // temp = temp->GetMethodAt(method_offset);
5355 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
5356 kArmWordSize).Int32Value();
5357 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
5358 // LR = temp->GetEntryPoint();
5359 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
5360 // LR();
5361 __ blx(LR);
5362}
5363
Vladimir Marko58155012015-08-19 12:49:41 +00005364void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
5365 DCHECK(linker_patches->empty());
5366 size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
5367 linker_patches->reserve(size);
5368 for (const auto& entry : method_patches_) {
5369 const MethodReference& target_method = entry.first;
5370 Literal* literal = entry.second;
5371 DCHECK(literal->GetLabel()->IsBound());
5372 uint32_t literal_offset = literal->GetLabel()->Position();
5373 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
5374 target_method.dex_file,
5375 target_method.dex_method_index));
5376 }
5377 for (const auto& entry : call_patches_) {
5378 const MethodReference& target_method = entry.first;
5379 Literal* literal = entry.second;
5380 DCHECK(literal->GetLabel()->IsBound());
5381 uint32_t literal_offset = literal->GetLabel()->Position();
5382 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
5383 target_method.dex_file,
5384 target_method.dex_method_index));
5385 }
5386 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
5387 uint32_t literal_offset = info.label.Position();
5388 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
5389 info.target_method.dex_file,
5390 info.target_method.dex_method_index));
5391 }
5392}
5393
5394Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
5395 MethodToLiteralMap* map) {
5396 // Look up the literal for target_method.
5397 auto lb = map->lower_bound(target_method);
5398 if (lb != map->end() && !map->key_comp()(target_method, lb->first)) {
5399 return lb->second;
5400 }
5401 // We don't have a literal for this method yet, insert a new one.
5402 Literal* literal = __ NewLiteral<uint32_t>(0u);
5403 map->PutBefore(lb, target_method, literal);
5404 return literal;
5405}
5406
5407Literal* CodeGeneratorARM::DeduplicateMethodAddressLiteral(MethodReference target_method) {
5408 return DeduplicateMethodLiteral(target_method, &method_patches_);
5409}
5410
5411Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_method) {
5412 return DeduplicateMethodLiteral(target_method, &call_patches_);
5413}
5414
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005415void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005416 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005417 LOG(FATAL) << "Unreachable";
5418}
5419
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005420void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00005421 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00005422 LOG(FATAL) << "Unreachable";
5423}
5424
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005425void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
5426 DCHECK(codegen_->IsBaseline());
5427 LocationSummary* locations =
5428 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5429 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5430}
5431
5432void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5433 DCHECK(codegen_->IsBaseline());
5434 // Will be generated at use site.
5435}
5436
Mark Mendellfe57faa2015-09-18 09:26:15 -04005437// Simple implementation of packed switch - generate cascaded compare/jumps.
5438void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5439 LocationSummary* locations =
5440 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5441 locations->SetInAt(0, Location::RequiresRegister());
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005442 if (switch_instr->GetNumEntries() >= kPackedSwitchJumpTableThreshold &&
5443 codegen_->GetAssembler()->IsThumb()) {
5444 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
5445 if (switch_instr->GetStartValue() != 0) {
5446 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
5447 }
5448 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04005449}
5450
5451void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5452 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005453 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04005454 LocationSummary* locations = switch_instr->GetLocations();
5455 Register value_reg = locations->InAt(0).AsRegister<Register>();
5456 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5457
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005458 if (num_entries < kPackedSwitchJumpTableThreshold || !codegen_->GetAssembler()->IsThumb()) {
5459 // Create a series of compare/jumps.
5460 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5461 for (uint32_t i = 0; i < num_entries; i++) {
5462 GenerateCompareWithImmediate(value_reg, lower_bound + i);
5463 __ b(codegen_->GetLabelOf(successors[i]), EQ);
5464 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04005465
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07005466 // And the default for any other value.
5467 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5468 __ b(codegen_->GetLabelOf(default_block));
5469 }
5470 } else {
5471 // Create a table lookup.
5472 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
5473
5474 // Materialize a pointer to the switch table
5475 std::vector<Label*> labels(num_entries);
5476 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5477 for (uint32_t i = 0; i < num_entries; i++) {
5478 labels[i] = codegen_->GetLabelOf(successors[i]);
5479 }
5480 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
5481
5482 // Remove the bias.
5483 Register key_reg;
5484 if (lower_bound != 0) {
5485 key_reg = locations->GetTemp(1).AsRegister<Register>();
5486 __ AddConstant(key_reg, value_reg, -lower_bound);
5487 } else {
5488 key_reg = value_reg;
5489 }
5490
5491 // Check whether the value is in the table, jump to default block if not.
5492 __ CmpConstant(key_reg, num_entries - 1);
5493 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
5494
5495 // Load the displacement from the table.
5496 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
5497
5498 // Dispatch is a direct add to the PC (for Thumb2).
5499 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04005500 }
5501}
5502
Andreas Gampe85b62f22015-09-09 13:15:38 -07005503void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
5504 if (!trg.IsValid()) {
5505 DCHECK(type == Primitive::kPrimVoid);
5506 return;
5507 }
5508
5509 DCHECK_NE(type, Primitive::kPrimVoid);
5510
5511 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
5512 if (return_loc.Equals(trg)) {
5513 return;
5514 }
5515
5516 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
5517 // with the last branch.
5518 if (type == Primitive::kPrimLong) {
5519 HParallelMove parallel_move(GetGraph()->GetArena());
5520 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
5521 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
5522 GetMoveResolver()->EmitNativeCode(&parallel_move);
5523 } else if (type == Primitive::kPrimDouble) {
5524 HParallelMove parallel_move(GetGraph()->GetArena());
5525 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
5526 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
5527 GetMoveResolver()->EmitNativeCode(&parallel_move);
5528 } else {
5529 // Let the parallel move resolver take care of all of this.
5530 HParallelMove parallel_move(GetGraph()->GetArena());
5531 parallel_move.AddMove(return_loc, trg, type, nullptr);
5532 GetMoveResolver()->EmitNativeCode(&parallel_move);
5533 }
5534}
5535
Roland Levillain4d027112015-07-01 15:41:14 +01005536#undef __
5537#undef QUICK_ENTRY_POINT
5538
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00005539} // namespace arm
5540} // namespace art