blob: ec0d56d291e1237b0fced96e93ef95be2861876d [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"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070022#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010023#include "gc/accounting/card_table.h"
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -080024#include "intrinsics.h"
25#include "intrinsics_arm.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070026#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070027#include "mirror/class-inl.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070028#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010029#include "utils/arm/assembler_arm.h"
30#include "utils/arm/managed_register_arm.h"
Roland Levillain946e1432014-11-11 17:35:19 +000031#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010032#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000033
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000034namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010035
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000036namespace arm {
37
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000038static bool ExpectedPairLayout(Location location) {
39 // We expected this for both core and fpu register pairs.
40 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
41}
42
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010043static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010044static constexpr Register kMethodRegisterArgument = R0;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010045
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000046// We unconditionally allocate R5 to ensure we can do long operations
47// with baseline.
48static constexpr Register kCoreSavedRegisterForBaseline = R5;
49static constexpr Register kCoreCalleeSaves[] =
50 { R5, R6, R7, R8, R10, R11, PC };
51static constexpr SRegister kFpuCalleeSaves[] =
52 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010053
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000054// D31 cannot be split into two S registers, and the register allocator only works on
55// S registers. Therefore there is no need to block it.
56static constexpr DRegister DTMP = D31;
57
Roland Levillain62a46b22015-06-01 18:24:13 +010058#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())->
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010059#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010060
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010061class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010062 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010063 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010064
Alexandre Rames67555f72014-11-18 10:55:16 +000065 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010066 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010067 __ Bind(GetEntryLabel());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +010068 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000069 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraye5038322014-07-04 09:41:32 +010070 }
71
72 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010073 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010074 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
75};
76
Calin Juravled0d48522014-11-04 16:40:20 +000077class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
78 public:
79 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
80
Alexandre Rames67555f72014-11-18 10:55:16 +000081 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000082 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
83 __ Bind(GetEntryLabel());
84 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000085 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
Calin Juravled0d48522014-11-04 16:40:20 +000086 }
87
88 private:
89 HDivZeroCheck* const instruction_;
90 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
91};
92
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010093class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000094 public:
Alexandre Rames67555f72014-11-18 10:55:16 +000095 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +010096 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000097
Alexandre Rames67555f72014-11-18 10:55:16 +000098 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010099 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000100 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000101 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100102 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000103 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000104 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100105 if (successor_ == nullptr) {
106 __ b(GetReturnLabel());
107 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100108 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100109 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000110 }
111
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100112 Label* GetReturnLabel() {
113 DCHECK(successor_ == nullptr);
114 return &return_label_;
115 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000116
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100117 HBasicBlock* GetSuccessor() const {
118 return successor_;
119 }
120
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000121 private:
122 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100123 // If not null, the block to branch to after the suspend check.
124 HBasicBlock* const successor_;
125
126 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000127 Label return_label_;
128
129 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
130};
131
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100132class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100133 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100134 BoundsCheckSlowPathARM(HBoundsCheck* instruction,
135 Location index_location,
136 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100137 : instruction_(instruction),
138 index_location_(index_location),
139 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100140
Alexandre Rames67555f72014-11-18 10:55:16 +0000141 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100142 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100143 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000144 // We're moving two locations to locations that could overlap, so we need a parallel
145 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100146 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000147 codegen->EmitParallelMoves(
148 index_location_,
149 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100150 Primitive::kPrimInt,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000151 length_location_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100152 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
153 Primitive::kPrimInt);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100154 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000155 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100156 }
157
158 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100159 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100160 const Location index_location_;
161 const Location length_location_;
162
163 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
164};
165
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000166class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100167 public:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000168 LoadClassSlowPathARM(HLoadClass* cls,
169 HInstruction* at,
170 uint32_t dex_pc,
171 bool do_clinit)
172 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
173 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
174 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100175
Alexandre Rames67555f72014-11-18 10:55:16 +0000176 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000177 LocationSummary* locations = at_->GetLocations();
178
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100179 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
180 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000181 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100182
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100183 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000184 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000185 int32_t entry_point_offset = do_clinit_
186 ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
187 : QUICK_ENTRY_POINT(pInitializeType);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000188 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000189
190 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000191 Location out = locations->Out();
192 if (out.IsValid()) {
193 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000194 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
195 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000196 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100197 __ b(GetExitLabel());
198 }
199
200 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000201 // The class this slow path will load.
202 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100203
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000204 // The instruction where this slow path is happening.
205 // (Might be the load class or an initialization check).
206 HInstruction* const at_;
207
208 // The dex PC of `at_`.
209 const uint32_t dex_pc_;
210
211 // Whether to initialize the class.
212 const bool do_clinit_;
213
214 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100215};
216
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000217class LoadStringSlowPathARM : public SlowPathCodeARM {
218 public:
219 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {}
220
Alexandre Rames67555f72014-11-18 10:55:16 +0000221 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000222 LocationSummary* locations = instruction_->GetLocations();
223 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
224
225 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
226 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000227 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000228
229 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800230 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000231 arm_codegen->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000232 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000233 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
234
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000235 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000236 __ b(GetExitLabel());
237 }
238
239 private:
240 HLoadString* const instruction_;
241
242 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
243};
244
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000245class TypeCheckSlowPathARM : public SlowPathCodeARM {
246 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000247 TypeCheckSlowPathARM(HInstruction* instruction,
248 Location class_to_check,
249 Location object_class,
250 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000251 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000252 class_to_check_(class_to_check),
253 object_class_(object_class),
254 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000255
Alexandre Rames67555f72014-11-18 10:55:16 +0000256 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000257 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000258 DCHECK(instruction_->IsCheckCast()
259 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000260
261 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
262 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000263 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000264
265 // We're moving two locations to locations that could overlap, so we need a parallel
266 // move resolver.
267 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000268 codegen->EmitParallelMoves(
269 class_to_check_,
270 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100271 Primitive::kPrimNot,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000272 object_class_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100273 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
274 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000275
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000276 if (instruction_->IsInstanceOf()) {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000277 arm_codegen->InvokeRuntime(
278 QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_, this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000279 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
280 } else {
281 DCHECK(instruction_->IsCheckCast());
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000282 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_, this);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000283 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000284
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000285 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000286 __ b(GetExitLabel());
287 }
288
289 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000290 HInstruction* const instruction_;
291 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000292 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000293 uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000294
295 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
296};
297
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700298class DeoptimizationSlowPathARM : public SlowPathCodeARM {
299 public:
300 explicit DeoptimizationSlowPathARM(HInstruction* instruction)
301 : instruction_(instruction) {}
302
303 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
304 __ Bind(GetEntryLabel());
305 SaveLiveRegisters(codegen, instruction_->GetLocations());
306 DCHECK(instruction_->IsDeoptimize());
307 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
308 uint32_t dex_pc = deoptimize->GetDexPc();
309 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
310 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
311 }
312
313 private:
314 HInstruction* const instruction_;
315 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
316};
317
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000318#undef __
319
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100320#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100321#define __ down_cast<ArmAssembler*>(GetAssembler())->
Dave Allison20dfc792014-06-16 20:44:29 -0700322
323inline Condition ARMCondition(IfCondition cond) {
324 switch (cond) {
325 case kCondEQ: return EQ;
326 case kCondNE: return NE;
327 case kCondLT: return LT;
328 case kCondLE: return LE;
329 case kCondGT: return GT;
330 case kCondGE: return GE;
331 default:
332 LOG(FATAL) << "Unknown if condition";
333 }
334 return EQ; // Unreachable.
335}
336
337inline Condition ARMOppositeCondition(IfCondition cond) {
338 switch (cond) {
339 case kCondEQ: return NE;
340 case kCondNE: return EQ;
341 case kCondLT: return GE;
342 case kCondLE: return GT;
343 case kCondGT: return LE;
344 case kCondGE: return LT;
345 default:
346 LOG(FATAL) << "Unknown if condition";
347 }
348 return EQ; // Unreachable.
349}
350
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100351void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100352 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100353}
354
355void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100356 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100357}
358
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100359size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
360 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
361 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100362}
363
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100364size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
365 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
366 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100367}
368
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000369size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
370 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
371 return kArmWordSize;
372}
373
374size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
375 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
376 return kArmWordSize;
377}
378
Calin Juravle34166012014-12-19 17:22:29 +0000379CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000380 const ArmInstructionSetFeatures& isa_features,
381 const CompilerOptions& compiler_options)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000382 : CodeGenerator(graph,
383 kNumberOfCoreRegisters,
384 kNumberOfSRegisters,
385 kNumberOfRegisterPairs,
386 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
387 arraysize(kCoreCalleeSaves)),
388 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
389 arraysize(kFpuCalleeSaves)),
390 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100391 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100392 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100393 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100394 move_resolver_(graph->GetArena(), this),
Vladimir Markof38caa62015-05-29 15:50:18 +0100395 assembler_(),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000396 isa_features_(isa_features) {
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000397 // Save the PC register to mimic Quick.
398 AddAllocatedRegister(Location::RegisterLocation(PC));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100399}
400
Vladimir Markof38caa62015-05-29 15:50:18 +0100401void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
402 // Ensure that we fix up branches and literal loads and emit the literal pool.
403 __ FinalizeCode();
404
405 // Adjust native pc offsets in stack maps.
406 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
407 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
408 uint32_t new_position = __ GetAdjustedPosition(old_position);
409 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
410 }
411
412 CodeGenerator::Finalize(allocator);
413}
414
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100415Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100416 switch (type) {
417 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100418 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100419 ArmManagedRegister pair =
420 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100421 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
422 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
423
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100424 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
425 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100426 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100427 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100428 }
429
430 case Primitive::kPrimByte:
431 case Primitive::kPrimBoolean:
432 case Primitive::kPrimChar:
433 case Primitive::kPrimShort:
434 case Primitive::kPrimInt:
435 case Primitive::kPrimNot: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100436 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100437 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100438 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
439 ArmManagedRegister current =
440 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
441 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100442 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100443 }
444 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100445 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100446 }
447
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000448 case Primitive::kPrimFloat: {
449 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100450 return Location::FpuRegisterLocation(reg);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100451 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100452
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000453 case Primitive::kPrimDouble: {
Nicolas Geoffray3c035032014-10-28 10:46:40 +0000454 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters);
455 DCHECK_EQ(reg % 2, 0);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000456 return Location::FpuRegisterPairLocation(reg, reg + 1);
457 }
458
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100459 case Primitive::kPrimVoid:
460 LOG(FATAL) << "Unreachable type " << type;
461 }
462
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100463 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100464}
465
Nicolas Geoffraya0bb2bd2015-01-26 12:49:35 +0000466void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100467 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100468 blocked_register_pairs_[R1_R2] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100469
470 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100471 blocked_core_registers_[SP] = true;
472 blocked_core_registers_[LR] = true;
473 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100474
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100475 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100476 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100477
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100478 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100479 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +0100480
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000481 if (is_baseline) {
482 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
483 blocked_core_registers_[kCoreCalleeSaves[i]] = true;
484 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000485
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000486 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false;
487
488 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
489 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
490 }
491 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100492
493 UpdateBlockedPairRegisters();
494}
495
496void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
497 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
498 ArmManagedRegister current =
499 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
500 if (blocked_core_registers_[current.AsRegisterPairLow()]
501 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
502 blocked_register_pairs_[i] = true;
503 }
504 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100505}
506
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100507InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
508 : HGraphVisitor(graph),
509 assembler_(codegen->GetAssembler()),
510 codegen_(codegen) {}
511
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000512void CodeGeneratorARM::ComputeSpillMask() {
513 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000514 // Save one extra register for baseline. Note that on thumb2, there is no easy
515 // instruction to restore just the PC, so this actually helps both baseline
516 // and non-baseline to save and restore at least two registers at entry and exit.
517 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000518 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
519 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
520 // We use vpush and vpop for saving and restoring floating point registers, which take
521 // a SRegister and the number of registers to save/restore after that SRegister. We
522 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
523 // but in the range.
524 if (fpu_spill_mask_ != 0) {
525 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
526 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
527 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
528 fpu_spill_mask_ |= (1 << i);
529 }
530 }
531}
532
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100533static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100534 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100535}
536
537static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100538 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100539}
540
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000541void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +0000542 bool skip_overflow_check =
543 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000544 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000545 __ Bind(&frame_entry_label_);
546
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000547 if (HasEmptyFrame()) {
548 return;
549 }
550
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100551 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000552 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
553 __ LoadFromOffset(kLoadWord, IP, IP, 0);
554 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100555 }
556
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000557 // PC is in the list of callee-save to mimic Quick, but we need to push
558 // LR at entry instead.
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100559 uint32_t push_mask = (core_spill_mask_ & (~(1 << PC))) | 1 << LR;
560 __ PushList(push_mask);
561 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(push_mask));
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100562 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, push_mask, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000563 if (fpu_spill_mask_ != 0) {
564 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
565 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100566 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +0100567 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000568 }
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100569 int adjust = GetFrameSize() - FrameEntrySpillSize();
570 __ AddConstant(SP, -adjust);
571 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100572 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000573}
574
575void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000576 if (HasEmptyFrame()) {
577 __ bx(LR);
578 return;
579 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100580 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100581 int adjust = GetFrameSize() - FrameEntrySpillSize();
582 __ AddConstant(SP, adjust);
583 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000584 if (fpu_spill_mask_ != 0) {
585 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
586 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100587 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_));
588 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +0000589 }
590 __ PopList(core_spill_mask_);
David Srbeckyc34dc932015-04-12 09:27:43 +0100591 __ cfi().RestoreState();
592 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000593}
594
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100595void CodeGeneratorARM::Bind(HBasicBlock* block) {
596 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000597}
598
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100599Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
600 switch (load->GetType()) {
601 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100602 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100603 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100604
605 case Primitive::kPrimInt:
606 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100607 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100608 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100609
610 case Primitive::kPrimBoolean:
611 case Primitive::kPrimByte:
612 case Primitive::kPrimChar:
613 case Primitive::kPrimShort:
614 case Primitive::kPrimVoid:
615 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700616 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100617 }
618
619 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700620 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100621}
622
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100623Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100624 switch (type) {
625 case Primitive::kPrimBoolean:
626 case Primitive::kPrimByte:
627 case Primitive::kPrimChar:
628 case Primitive::kPrimShort:
629 case Primitive::kPrimInt:
630 case Primitive::kPrimNot: {
631 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000632 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100633 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100634 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100635 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000636 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100637 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100638 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100639
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000640 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100641 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000642 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100643 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000644 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100645 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000646 if (calling_convention.GetRegisterAt(index) == R1) {
647 // Skip R1, and use R2_R3 instead.
648 gp_index_++;
649 index++;
650 }
651 }
652 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
653 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000654 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000655 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +0000656 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100657 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000658 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
659 }
660 }
661
662 case Primitive::kPrimFloat: {
663 uint32_t stack_index = stack_index_++;
664 if (float_index_ % 2 == 0) {
665 float_index_ = std::max(double_index_, float_index_);
666 }
667 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
668 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
669 } else {
670 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
671 }
672 }
673
674 case Primitive::kPrimDouble: {
675 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
676 uint32_t stack_index = stack_index_;
677 stack_index_ += 2;
678 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
679 uint32_t index = double_index_;
680 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000681 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000682 calling_convention.GetFpuRegisterAt(index),
683 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000684 DCHECK(ExpectedPairLayout(result));
685 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000686 } else {
687 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100688 }
689 }
690
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100691 case Primitive::kPrimVoid:
692 LOG(FATAL) << "Unexpected parameter type " << type;
693 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100694 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100695 return Location();
696}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100697
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100698Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000699 switch (type) {
700 case Primitive::kPrimBoolean:
701 case Primitive::kPrimByte:
702 case Primitive::kPrimChar:
703 case Primitive::kPrimShort:
704 case Primitive::kPrimInt:
705 case Primitive::kPrimNot: {
706 return Location::RegisterLocation(R0);
707 }
708
709 case Primitive::kPrimFloat: {
710 return Location::FpuRegisterLocation(S0);
711 }
712
713 case Primitive::kPrimLong: {
714 return Location::RegisterPairLocation(R0, R1);
715 }
716
717 case Primitive::kPrimDouble: {
718 return Location::FpuRegisterPairLocation(S0, S1);
719 }
720
721 case Primitive::kPrimVoid:
722 return Location();
723 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100724
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000725 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000726}
727
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100728Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
729 return Location::RegisterLocation(kMethodRegisterArgument);
730}
731
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100732void CodeGeneratorARM::Move32(Location destination, Location source) {
733 if (source.Equals(destination)) {
734 return;
735 }
736 if (destination.IsRegister()) {
737 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000738 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100739 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000740 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100741 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000742 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100743 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100744 } else if (destination.IsFpuRegister()) {
745 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000746 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100747 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000748 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100749 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000750 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100751 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100752 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000753 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100754 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000755 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100756 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000757 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100758 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +0000759 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100760 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
761 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100762 }
763 }
764}
765
766void CodeGeneratorARM::Move64(Location destination, Location source) {
767 if (source.Equals(destination)) {
768 return;
769 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100770 if (destination.IsRegisterPair()) {
771 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000772 EmitParallelMoves(
773 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
774 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100775 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000776 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100777 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
778 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100779 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000780 UNIMPLEMENTED(FATAL);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100781 } else {
782 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000783 DCHECK(ExpectedPairLayout(destination));
784 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
785 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100786 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000787 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100788 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000789 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
790 SP,
791 source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100792 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000793 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100794 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100795 } else {
796 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100797 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000798 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100799 if (source.AsRegisterPairLow<Register>() == R1) {
800 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100801 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
802 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100803 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100804 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100805 SP, destination.GetStackIndex());
806 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +0000807 } else if (source.IsFpuRegisterPair()) {
808 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
809 SP,
810 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100811 } else {
812 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000813 EmitParallelMoves(
814 Location::StackSlot(source.GetStackIndex()),
815 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100816 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000817 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100818 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
819 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100820 }
821 }
822}
823
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100824void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100825 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100826 if (instruction->IsCurrentMethod()) {
827 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
828 } else if (locations != nullptr && locations->Out().Equals(location)) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100829 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100830 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000831 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000832 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
833 int32_t value = GetInt32ValueOf(const_to_move);
Calin Juravlea21f5982014-11-13 15:53:04 +0000834 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000835 __ LoadImmediate(location.AsRegister<Register>(), value);
Calin Juravlea21f5982014-11-13 15:53:04 +0000836 } else {
837 DCHECK(location.IsStackSlot());
838 __ LoadImmediate(IP, value);
839 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
840 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000841 } else {
Nicolas Geoffray3747b482015-01-19 17:17:16 +0000842 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
Calin Juravlea21f5982014-11-13 15:53:04 +0000843 int64_t value = const_to_move->AsLongConstant()->GetValue();
844 if (location.IsRegisterPair()) {
845 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
846 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
847 } else {
848 DCHECK(location.IsDoubleStackSlot());
849 __ LoadImmediate(IP, Low32Bits(value));
850 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
851 __ LoadImmediate(IP, High32Bits(value));
852 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
853 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100854 }
Roland Levillain476df552014-10-09 17:51:36 +0100855 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100856 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
857 switch (instruction->GetType()) {
858 case Primitive::kPrimBoolean:
859 case Primitive::kPrimByte:
860 case Primitive::kPrimChar:
861 case Primitive::kPrimShort:
862 case Primitive::kPrimInt:
863 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100864 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100865 Move32(location, Location::StackSlot(stack_slot));
866 break;
867
868 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100869 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100870 Move64(location, Location::DoubleStackSlot(stack_slot));
871 break;
872
873 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100874 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100875 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000876 } else if (instruction->IsTemporary()) {
877 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000878 if (temp_location.IsStackSlot()) {
879 Move32(location, temp_location);
880 } else {
881 DCHECK(temp_location.IsDoubleStackSlot());
882 Move64(location, temp_location);
883 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000884 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100885 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100886 switch (instruction->GetType()) {
887 case Primitive::kPrimBoolean:
888 case Primitive::kPrimByte:
889 case Primitive::kPrimChar:
890 case Primitive::kPrimShort:
891 case Primitive::kPrimNot:
892 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100893 case Primitive::kPrimFloat:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100894 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100895 break;
896
897 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100898 case Primitive::kPrimDouble:
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100899 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100900 break;
901
902 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100903 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100904 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000905 }
906}
907
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100908void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
909 HInstruction* instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000910 uint32_t dex_pc,
911 SlowPathCode* slow_path) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100912 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
913 __ blx(LR);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000914 RecordPcInfo(instruction, dex_pc, slow_path);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100915 DCHECK(instruction->IsSuspendCheck()
916 || instruction->IsBoundsCheck()
917 || instruction->IsNullCheck()
Calin Juravled0d48522014-11-04 16:40:20 +0000918 || instruction->IsDivZeroCheck()
Roland Levillain624279f2014-12-04 11:54:28 +0000919 || instruction->GetLocations()->CanCall()
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100920 || !IsLeafMethod());
921}
922
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000923void LocationsBuilderARM::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000924 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000925}
926
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000927void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000928 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100929 DCHECK(!successor->IsExitBlock());
930
931 HBasicBlock* block = got->GetBlock();
932 HInstruction* previous = got->GetPrevious();
933
934 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000935 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100936 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
937 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
938 return;
939 }
940
941 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
942 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
943 }
944 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000945 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000946 }
947}
948
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000949void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000950 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000951}
952
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000953void InstructionCodeGeneratorARM::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700954 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000955}
956
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700957void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
958 Label* true_target,
959 Label* false_target,
960 Label* always_true_target) {
961 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100962 if (cond->IsIntConstant()) {
963 // Constant condition, statically compared against 1.
964 int32_t cond_value = cond->AsIntConstant()->GetValue();
965 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700966 if (always_true_target != nullptr) {
967 __ b(always_true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100968 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100969 return;
970 } else {
971 DCHECK_EQ(cond_value, 0);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100972 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100973 } else {
974 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
975 // Condition has been materialized, compare the output to 0
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700976 DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
977 __ cmp(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100978 ShifterOperand(0));
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700979 __ b(true_target, NE);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100980 } else {
981 // Condition has not been materialized, use its inputs as the
982 // comparison and its condition as the branch condition.
983 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +0000984 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000985 Register left = locations->InAt(0).AsRegister<Register>();
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100986 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000987 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100988 } else {
989 DCHECK(locations->InAt(1).IsConstant());
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000990 HConstant* constant = locations->InAt(1).GetConstant();
991 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100992 ShifterOperand operand;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000993 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
994 __ cmp(left, operand);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100995 } else {
996 Register temp = IP;
997 __ LoadImmediate(temp, value);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000998 __ cmp(left, ShifterOperand(temp));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100999 }
1000 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001001 __ b(true_target, ARMCondition(cond->AsCondition()->GetCondition()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001002 }
Dave Allison20dfc792014-06-16 20:44:29 -07001003 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001004 if (false_target != nullptr) {
1005 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001006 }
1007}
1008
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001009void LocationsBuilderARM::VisitIf(HIf* if_instr) {
1010 LocationSummary* locations =
1011 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1012 HInstruction* cond = if_instr->InputAt(0);
1013 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1014 locations->SetInAt(0, Location::RequiresRegister());
1015 }
1016}
1017
1018void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
1019 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1020 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1021 Label* always_true_target = true_target;
1022 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1023 if_instr->IfTrueSuccessor())) {
1024 always_true_target = nullptr;
1025 }
1026 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1027 if_instr->IfFalseSuccessor())) {
1028 false_target = nullptr;
1029 }
1030 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1031}
1032
1033void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1034 LocationSummary* locations = new (GetGraph()->GetArena())
1035 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1036 HInstruction* cond = deoptimize->InputAt(0);
1037 DCHECK(cond->IsCondition());
1038 if (cond->AsCondition()->NeedsMaterialization()) {
1039 locations->SetInAt(0, Location::RequiresRegister());
1040 }
1041}
1042
1043void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
1044 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
1045 DeoptimizationSlowPathARM(deoptimize);
1046 codegen_->AddSlowPath(slow_path);
1047 Label* slow_path_entry = slow_path->GetEntryLabel();
1048 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1049}
Dave Allison20dfc792014-06-16 20:44:29 -07001050
Roland Levillain0d37cd02015-05-27 16:39:19 +01001051void LocationsBuilderARM::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001052 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001053 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001054 locations->SetInAt(0, Location::RequiresRegister());
Roland Levillain0d37cd02015-05-27 16:39:19 +01001055 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1056 if (cond->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001057 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001058 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001059}
1060
Roland Levillain0d37cd02015-05-27 16:39:19 +01001061void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
1062 if (!cond->NeedsMaterialization()) return;
1063 LocationSummary* locations = cond->GetLocations();
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001064 Register left = locations->InAt(0).AsRegister<Register>();
1065
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001066 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001067 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001068 } else {
1069 DCHECK(locations->InAt(1).IsConstant());
Mingyao Yangdc5ac732015-02-25 11:28:05 -08001070 int32_t value = CodeGenerator::GetInt32ValueOf(locations->InAt(1).GetConstant());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001071 ShifterOperand operand;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001072 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
1073 __ cmp(left, operand);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001074 } else {
1075 Register temp = IP;
1076 __ LoadImmediate(temp, value);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00001077 __ cmp(left, ShifterOperand(temp));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001078 }
Dave Allison20dfc792014-06-16 20:44:29 -07001079 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001080 __ it(ARMCondition(cond->GetCondition()), kItElse);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001081 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
Roland Levillain0d37cd02015-05-27 16:39:19 +01001082 ARMCondition(cond->GetCondition()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001083 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
Roland Levillain0d37cd02015-05-27 16:39:19 +01001084 ARMOppositeCondition(cond->GetCondition()));
Dave Allison20dfc792014-06-16 20:44:29 -07001085}
1086
1087void LocationsBuilderARM::VisitEqual(HEqual* comp) {
1088 VisitCondition(comp);
1089}
1090
1091void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
1092 VisitCondition(comp);
1093}
1094
1095void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
1096 VisitCondition(comp);
1097}
1098
1099void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
1100 VisitCondition(comp);
1101}
1102
1103void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
1104 VisitCondition(comp);
1105}
1106
1107void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
1108 VisitCondition(comp);
1109}
1110
1111void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1112 VisitCondition(comp);
1113}
1114
1115void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1116 VisitCondition(comp);
1117}
1118
1119void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
1120 VisitCondition(comp);
1121}
1122
1123void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
1124 VisitCondition(comp);
1125}
1126
1127void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1128 VisitCondition(comp);
1129}
1130
1131void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1132 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001133}
1134
1135void LocationsBuilderARM::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001136 local->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001137}
1138
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001139void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
1140 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001141}
1142
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001143void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001144 load->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001145}
1146
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001147void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001148 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001149 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001150}
1151
1152void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001153 LocationSummary* locations =
1154 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001155 switch (store->InputAt(1)->GetType()) {
1156 case Primitive::kPrimBoolean:
1157 case Primitive::kPrimByte:
1158 case Primitive::kPrimChar:
1159 case Primitive::kPrimShort:
1160 case Primitive::kPrimInt:
1161 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001162 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001163 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1164 break;
1165
1166 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001167 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001168 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1169 break;
1170
1171 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001172 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001173 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001174}
1175
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001176void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001177 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001178}
1179
1180void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001181 LocationSummary* locations =
1182 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001183 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001184}
1185
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001186void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001187 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001188 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001189}
1190
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001191void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
1192 LocationSummary* locations =
1193 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1194 locations->SetOut(Location::ConstantLocation(constant));
1195}
1196
1197void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
1198 // Will be generated at use site.
1199 UNUSED(constant);
1200}
1201
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001202void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001203 LocationSummary* locations =
1204 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001205 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001206}
1207
1208void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) {
1209 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001210 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001211}
1212
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001213void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
1214 LocationSummary* locations =
1215 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1216 locations->SetOut(Location::ConstantLocation(constant));
1217}
1218
1219void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
1220 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001221 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001222}
1223
1224void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
1225 LocationSummary* locations =
1226 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1227 locations->SetOut(Location::ConstantLocation(constant));
1228}
1229
1230void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
1231 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001232 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001233}
1234
Calin Juravle27df7582015-04-17 19:12:31 +01001235void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1236 memory_barrier->SetLocations(nullptr);
1237}
1238
1239void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1240 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1241}
1242
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001243void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001244 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001245}
1246
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001247void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001248 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001249 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001250}
1251
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001252void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001253 LocationSummary* locations =
1254 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001255 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001256}
1257
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001258void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001259 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001260 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001261}
1262
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001263void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001264 // When we do not run baseline, explicit clinit checks triggered by static
1265 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1266 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001267
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001268 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1269 codegen_->GetInstructionSetFeatures());
1270 if (intrinsic.TryDispatch(invoke)) {
1271 return;
1272 }
1273
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001274 HandleInvoke(invoke);
1275}
1276
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001277void CodeGeneratorARM::LoadCurrentMethod(Register reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00001278 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001279 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001280}
1281
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001282static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
1283 if (invoke->GetLocations()->Intrinsified()) {
1284 IntrinsicCodeGeneratorARM intrinsic(codegen);
1285 intrinsic.Dispatch(invoke);
1286 return true;
1287 }
1288 return false;
1289}
1290
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001291void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001292 // When we do not run baseline, explicit clinit checks triggered by static
1293 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1294 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001295
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001296 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1297 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001298 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001299
Nicolas Geoffrayc345f142015-06-04 17:17:32 +00001300 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
1301
1302 codegen_->GenerateStaticOrDirectCall(invoke, temp);
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00001303 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001304}
1305
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001306void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001307 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001308 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001309}
1310
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001311void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001312 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
1313 codegen_->GetInstructionSetFeatures());
1314 if (intrinsic.TryDispatch(invoke)) {
1315 return;
1316 }
1317
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001318 HandleInvoke(invoke);
1319}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001320
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001321void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08001322 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1323 return;
1324 }
1325
Roland Levillain271ab9c2014-11-27 15:23:57 +00001326 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001327 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1328 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001329 LocationSummary* locations = invoke->GetLocations();
1330 Location receiver = locations->InAt(0);
1331 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1332 // temp = object->GetClass();
Nicolas Geoffrayc345f142015-06-04 17:17:32 +00001333 if (receiver.IsStackSlot()) {
1334 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1335 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1336 } else {
1337 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
1338 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001339 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001340 // temp = temp->GetMethodAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001341 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001342 kArmWordSize).Int32Value();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001343 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001344 // LR = temp->GetEntryPoint();
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001345 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001346 // LR();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001347 __ blx(LR);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001348 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001349 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001350}
1351
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001352void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1353 HandleInvoke(invoke);
1354 // Add the hidden argument.
1355 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
1356}
1357
1358void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
1359 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001360 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001361 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1362 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001363 LocationSummary* locations = invoke->GetLocations();
1364 Location receiver = locations->InAt(0);
1365 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1366
1367 // Set the hidden argument.
Roland Levillain199f3362014-11-27 17:15:16 +00001368 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
1369 invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001370
1371 // temp = object->GetClass();
1372 if (receiver.IsStackSlot()) {
1373 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
1374 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
1375 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001376 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001377 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001378 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001379 // temp = temp->GetImtEntryAt(method_offset);
Mathieu Chartiere401d142015-04-22 13:56:20 -07001380 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001381 kArmWordSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001382 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
1383 // LR = temp->GetEntryPoint();
1384 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
1385 // LR();
1386 __ blx(LR);
1387 DCHECK(!codegen_->IsLeafMethod());
1388 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1389}
1390
Roland Levillain88cb1752014-10-20 16:36:47 +01001391void LocationsBuilderARM::VisitNeg(HNeg* neg) {
1392 LocationSummary* locations =
1393 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1394 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001395 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01001396 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001397 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1398 break;
1399 }
1400 case Primitive::kPrimLong: {
1401 locations->SetInAt(0, Location::RequiresRegister());
1402 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001403 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001404 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001405
Roland Levillain88cb1752014-10-20 16:36:47 +01001406 case Primitive::kPrimFloat:
1407 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001408 locations->SetInAt(0, Location::RequiresFpuRegister());
1409 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01001410 break;
1411
1412 default:
1413 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1414 }
1415}
1416
1417void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
1418 LocationSummary* locations = neg->GetLocations();
1419 Location out = locations->Out();
1420 Location in = locations->InAt(0);
1421 switch (neg->GetResultType()) {
1422 case Primitive::kPrimInt:
1423 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001424 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01001425 break;
1426
1427 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001428 DCHECK(in.IsRegisterPair());
1429 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
1430 __ rsbs(out.AsRegisterPairLow<Register>(),
1431 in.AsRegisterPairLow<Register>(),
1432 ShifterOperand(0));
1433 // We cannot emit an RSC (Reverse Subtract with Carry)
1434 // instruction here, as it does not exist in the Thumb-2
1435 // instruction set. We use the following approach
1436 // using SBC and SUB instead.
1437 //
1438 // out.hi = -C
1439 __ sbc(out.AsRegisterPairHigh<Register>(),
1440 out.AsRegisterPairHigh<Register>(),
1441 ShifterOperand(out.AsRegisterPairHigh<Register>()));
1442 // out.hi = out.hi - in.hi
1443 __ sub(out.AsRegisterPairHigh<Register>(),
1444 out.AsRegisterPairHigh<Register>(),
1445 ShifterOperand(in.AsRegisterPairHigh<Register>()));
1446 break;
1447
Roland Levillain88cb1752014-10-20 16:36:47 +01001448 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001449 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001450 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001451 break;
1452
Roland Levillain88cb1752014-10-20 16:36:47 +01001453 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001454 DCHECK(in.IsFpuRegisterPair());
1455 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1456 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01001457 break;
1458
1459 default:
1460 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1461 }
1462}
1463
Roland Levillaindff1f282014-11-05 14:15:05 +00001464void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001465 Primitive::Type result_type = conversion->GetResultType();
1466 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001467 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001468
Roland Levillain5b3ee562015-04-14 16:02:41 +01001469 // The float-to-long, double-to-long and long-to-float type conversions
1470 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001471 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01001472 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1473 && result_type == Primitive::kPrimLong)
1474 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Roland Levillain624279f2014-12-04 11:54:28 +00001475 ? LocationSummary::kCall
1476 : LocationSummary::kNoCall;
1477 LocationSummary* locations =
1478 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1479
David Brazdilb2bd1c52015-03-25 11:17:37 +00001480 // The Java language does not allow treating boolean as an integral type but
1481 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001482
Roland Levillaindff1f282014-11-05 14:15:05 +00001483 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001484 case Primitive::kPrimByte:
1485 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001486 case Primitive::kPrimBoolean:
1487 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001488 case Primitive::kPrimShort:
1489 case Primitive::kPrimInt:
1490 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001491 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001492 locations->SetInAt(0, Location::RequiresRegister());
1493 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1494 break;
1495
1496 default:
1497 LOG(FATAL) << "Unexpected type conversion from " << input_type
1498 << " to " << result_type;
1499 }
1500 break;
1501
Roland Levillain01a8d712014-11-14 16:27:39 +00001502 case Primitive::kPrimShort:
1503 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001504 case Primitive::kPrimBoolean:
1505 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001506 case Primitive::kPrimByte:
1507 case Primitive::kPrimInt:
1508 case Primitive::kPrimChar:
1509 // Processing a Dex `int-to-short' instruction.
1510 locations->SetInAt(0, Location::RequiresRegister());
1511 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1512 break;
1513
1514 default:
1515 LOG(FATAL) << "Unexpected type conversion from " << input_type
1516 << " to " << result_type;
1517 }
1518 break;
1519
Roland Levillain946e1432014-11-11 17:35:19 +00001520 case Primitive::kPrimInt:
1521 switch (input_type) {
1522 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001523 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001524 locations->SetInAt(0, Location::Any());
1525 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1526 break;
1527
1528 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001529 // Processing a Dex `float-to-int' instruction.
1530 locations->SetInAt(0, Location::RequiresFpuRegister());
1531 locations->SetOut(Location::RequiresRegister());
1532 locations->AddTemp(Location::RequiresFpuRegister());
1533 break;
1534
Roland Levillain946e1432014-11-11 17:35:19 +00001535 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001536 // Processing a Dex `double-to-int' instruction.
1537 locations->SetInAt(0, Location::RequiresFpuRegister());
1538 locations->SetOut(Location::RequiresRegister());
1539 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001540 break;
1541
1542 default:
1543 LOG(FATAL) << "Unexpected type conversion from " << input_type
1544 << " to " << result_type;
1545 }
1546 break;
1547
Roland Levillaindff1f282014-11-05 14:15:05 +00001548 case Primitive::kPrimLong:
1549 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001550 case Primitive::kPrimBoolean:
1551 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001552 case Primitive::kPrimByte:
1553 case Primitive::kPrimShort:
1554 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001555 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001556 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001557 locations->SetInAt(0, Location::RequiresRegister());
1558 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1559 break;
1560
Roland Levillain624279f2014-12-04 11:54:28 +00001561 case Primitive::kPrimFloat: {
1562 // Processing a Dex `float-to-long' instruction.
1563 InvokeRuntimeCallingConvention calling_convention;
1564 locations->SetInAt(0, Location::FpuRegisterLocation(
1565 calling_convention.GetFpuRegisterAt(0)));
1566 locations->SetOut(Location::RegisterPairLocation(R0, R1));
1567 break;
1568 }
1569
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001570 case Primitive::kPrimDouble: {
1571 // Processing a Dex `double-to-long' instruction.
1572 InvokeRuntimeCallingConvention calling_convention;
1573 locations->SetInAt(0, Location::FpuRegisterPairLocation(
1574 calling_convention.GetFpuRegisterAt(0),
1575 calling_convention.GetFpuRegisterAt(1)));
1576 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00001577 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001578 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001579
1580 default:
1581 LOG(FATAL) << "Unexpected type conversion from " << input_type
1582 << " to " << result_type;
1583 }
1584 break;
1585
Roland Levillain981e4542014-11-14 11:47:14 +00001586 case Primitive::kPrimChar:
1587 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001588 case Primitive::kPrimBoolean:
1589 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001590 case Primitive::kPrimByte:
1591 case Primitive::kPrimShort:
1592 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001593 // Processing a Dex `int-to-char' instruction.
1594 locations->SetInAt(0, Location::RequiresRegister());
1595 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1596 break;
1597
1598 default:
1599 LOG(FATAL) << "Unexpected type conversion from " << input_type
1600 << " to " << result_type;
1601 }
1602 break;
1603
Roland Levillaindff1f282014-11-05 14:15:05 +00001604 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001605 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001606 case Primitive::kPrimBoolean:
1607 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001608 case Primitive::kPrimByte:
1609 case Primitive::kPrimShort:
1610 case Primitive::kPrimInt:
1611 case Primitive::kPrimChar:
1612 // Processing a Dex `int-to-float' instruction.
1613 locations->SetInAt(0, Location::RequiresRegister());
1614 locations->SetOut(Location::RequiresFpuRegister());
1615 break;
1616
Roland Levillain5b3ee562015-04-14 16:02:41 +01001617 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00001618 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01001619 InvokeRuntimeCallingConvention calling_convention;
1620 locations->SetInAt(0, Location::RegisterPairLocation(
1621 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
1622 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00001623 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01001624 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00001625
Roland Levillaincff13742014-11-17 14:32:17 +00001626 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001627 // Processing a Dex `double-to-float' instruction.
1628 locations->SetInAt(0, Location::RequiresFpuRegister());
1629 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001630 break;
1631
1632 default:
1633 LOG(FATAL) << "Unexpected type conversion from " << input_type
1634 << " to " << result_type;
1635 };
1636 break;
1637
Roland Levillaindff1f282014-11-05 14:15:05 +00001638 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001639 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001640 case Primitive::kPrimBoolean:
1641 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001642 case Primitive::kPrimByte:
1643 case Primitive::kPrimShort:
1644 case Primitive::kPrimInt:
1645 case Primitive::kPrimChar:
1646 // Processing a Dex `int-to-double' instruction.
1647 locations->SetInAt(0, Location::RequiresRegister());
1648 locations->SetOut(Location::RequiresFpuRegister());
1649 break;
1650
1651 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001652 // Processing a Dex `long-to-double' instruction.
1653 locations->SetInAt(0, Location::RequiresRegister());
1654 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01001655 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001656 locations->AddTemp(Location::RequiresFpuRegister());
1657 break;
1658
Roland Levillaincff13742014-11-17 14:32:17 +00001659 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001660 // Processing a Dex `float-to-double' instruction.
1661 locations->SetInAt(0, Location::RequiresFpuRegister());
1662 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001663 break;
1664
1665 default:
1666 LOG(FATAL) << "Unexpected type conversion from " << input_type
1667 << " to " << result_type;
1668 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001669 break;
1670
1671 default:
1672 LOG(FATAL) << "Unexpected type conversion from " << input_type
1673 << " to " << result_type;
1674 }
1675}
1676
1677void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
1678 LocationSummary* locations = conversion->GetLocations();
1679 Location out = locations->Out();
1680 Location in = locations->InAt(0);
1681 Primitive::Type result_type = conversion->GetResultType();
1682 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001683 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001684 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001685 case Primitive::kPrimByte:
1686 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001687 case Primitive::kPrimBoolean:
1688 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001689 case Primitive::kPrimShort:
1690 case Primitive::kPrimInt:
1691 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001692 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001693 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001694 break;
1695
1696 default:
1697 LOG(FATAL) << "Unexpected type conversion from " << input_type
1698 << " to " << result_type;
1699 }
1700 break;
1701
Roland Levillain01a8d712014-11-14 16:27:39 +00001702 case Primitive::kPrimShort:
1703 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001704 case Primitive::kPrimBoolean:
1705 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001706 case Primitive::kPrimByte:
1707 case Primitive::kPrimInt:
1708 case Primitive::kPrimChar:
1709 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001710 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00001711 break;
1712
1713 default:
1714 LOG(FATAL) << "Unexpected type conversion from " << input_type
1715 << " to " << result_type;
1716 }
1717 break;
1718
Roland Levillain946e1432014-11-11 17:35:19 +00001719 case Primitive::kPrimInt:
1720 switch (input_type) {
1721 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001722 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001723 DCHECK(out.IsRegister());
1724 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001725 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001726 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001727 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00001728 } else {
1729 DCHECK(in.IsConstant());
1730 DCHECK(in.GetConstant()->IsLongConstant());
1731 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001732 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00001733 }
1734 break;
1735
Roland Levillain3f8f9362014-12-02 17:45:01 +00001736 case Primitive::kPrimFloat: {
1737 // Processing a Dex `float-to-int' instruction.
1738 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1739 __ vmovs(temp, in.AsFpuRegister<SRegister>());
1740 __ vcvtis(temp, temp);
1741 __ vmovrs(out.AsRegister<Register>(), temp);
1742 break;
1743 }
1744
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001745 case Primitive::kPrimDouble: {
1746 // Processing a Dex `double-to-int' instruction.
1747 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
1748 DRegister temp_d = FromLowSToD(temp_s);
1749 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
1750 __ vcvtid(temp_s, temp_d);
1751 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00001752 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001753 }
Roland Levillain946e1432014-11-11 17:35:19 +00001754
1755 default:
1756 LOG(FATAL) << "Unexpected type conversion from " << input_type
1757 << " to " << result_type;
1758 }
1759 break;
1760
Roland Levillaindff1f282014-11-05 14:15:05 +00001761 case Primitive::kPrimLong:
1762 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001763 case Primitive::kPrimBoolean:
1764 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001765 case Primitive::kPrimByte:
1766 case Primitive::kPrimShort:
1767 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001768 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001769 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001770 DCHECK(out.IsRegisterPair());
1771 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00001772 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00001773 // Sign extension.
1774 __ Asr(out.AsRegisterPairHigh<Register>(),
1775 out.AsRegisterPairLow<Register>(),
1776 31);
1777 break;
1778
1779 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001780 // Processing a Dex `float-to-long' instruction.
Roland Levillain624279f2014-12-04 11:54:28 +00001781 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
1782 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001783 conversion->GetDexPc(),
1784 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00001785 break;
1786
Roland Levillaindff1f282014-11-05 14:15:05 +00001787 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001788 // Processing a Dex `double-to-long' instruction.
1789 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
1790 conversion,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00001791 conversion->GetDexPc(),
1792 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00001793 break;
1794
1795 default:
1796 LOG(FATAL) << "Unexpected type conversion from " << input_type
1797 << " to " << result_type;
1798 }
1799 break;
1800
Roland Levillain981e4542014-11-14 11:47:14 +00001801 case Primitive::kPrimChar:
1802 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001803 case Primitive::kPrimBoolean:
1804 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001805 case Primitive::kPrimByte:
1806 case Primitive::kPrimShort:
1807 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001808 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001809 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00001810 break;
1811
1812 default:
1813 LOG(FATAL) << "Unexpected type conversion from " << input_type
1814 << " to " << result_type;
1815 }
1816 break;
1817
Roland Levillaindff1f282014-11-05 14:15:05 +00001818 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001819 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001820 case Primitive::kPrimBoolean:
1821 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001822 case Primitive::kPrimByte:
1823 case Primitive::kPrimShort:
1824 case Primitive::kPrimInt:
1825 case Primitive::kPrimChar: {
1826 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001827 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
1828 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001829 break;
1830 }
1831
Roland Levillain5b3ee562015-04-14 16:02:41 +01001832 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001833 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01001834 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
1835 conversion,
1836 conversion->GetDexPc(),
1837 nullptr);
Roland Levillain6d0e4832014-11-27 18:31:21 +00001838 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00001839
Roland Levillaincff13742014-11-17 14:32:17 +00001840 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001841 // Processing a Dex `double-to-float' instruction.
1842 __ vcvtsd(out.AsFpuRegister<SRegister>(),
1843 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00001844 break;
1845
1846 default:
1847 LOG(FATAL) << "Unexpected type conversion from " << input_type
1848 << " to " << result_type;
1849 };
1850 break;
1851
Roland Levillaindff1f282014-11-05 14:15:05 +00001852 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001853 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001854 case Primitive::kPrimBoolean:
1855 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001856 case Primitive::kPrimByte:
1857 case Primitive::kPrimShort:
1858 case Primitive::kPrimInt:
1859 case Primitive::kPrimChar: {
1860 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001861 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001862 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1863 out.AsFpuRegisterPairLow<SRegister>());
1864 break;
1865 }
1866
Roland Levillain647b9ed2014-11-27 12:06:00 +00001867 case Primitive::kPrimLong: {
1868 // Processing a Dex `long-to-double' instruction.
1869 Register low = in.AsRegisterPairLow<Register>();
1870 Register high = in.AsRegisterPairHigh<Register>();
1871 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
1872 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01001873 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00001874 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01001875 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
1876 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001877
Roland Levillain682393c2015-04-14 15:57:52 +01001878 // temp_d = int-to-double(high)
1879 __ vmovsr(temp_s, high);
1880 __ vcvtdi(temp_d, temp_s);
1881 // constant_d = k2Pow32EncodingForDouble
1882 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
1883 // out_d = unsigned-to-double(low)
1884 __ vmovsr(out_s, low);
1885 __ vcvtdu(out_d, out_s);
1886 // out_d += temp_d * constant_d
1887 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001888 break;
1889 }
1890
Roland Levillaincff13742014-11-17 14:32:17 +00001891 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001892 // Processing a Dex `float-to-double' instruction.
1893 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1894 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001895 break;
1896
1897 default:
1898 LOG(FATAL) << "Unexpected type conversion from " << input_type
1899 << " to " << result_type;
1900 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001901 break;
1902
1903 default:
1904 LOG(FATAL) << "Unexpected type conversion from " << input_type
1905 << " to " << result_type;
1906 }
1907}
1908
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001909void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001910 LocationSummary* locations =
1911 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001912 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001913 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001914 locations->SetInAt(0, Location::RequiresRegister());
1915 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001916 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1917 break;
1918 }
1919
1920 case Primitive::kPrimLong: {
1921 locations->SetInAt(0, Location::RequiresRegister());
1922 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00001923 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001924 break;
1925 }
1926
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001927 case Primitive::kPrimFloat:
1928 case Primitive::kPrimDouble: {
1929 locations->SetInAt(0, Location::RequiresFpuRegister());
1930 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00001931 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001932 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001933 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001934
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001935 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001936 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001937 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001938}
1939
1940void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
1941 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001942 Location out = locations->Out();
1943 Location first = locations->InAt(0);
1944 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001945 switch (add->GetResultType()) {
1946 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001947 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001948 __ add(out.AsRegister<Register>(),
1949 first.AsRegister<Register>(),
1950 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001951 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001952 __ AddConstant(out.AsRegister<Register>(),
1953 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001954 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001955 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001956 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001957
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001958 case Primitive::kPrimLong: {
1959 DCHECK(second.IsRegisterPair());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001960 __ adds(out.AsRegisterPairLow<Register>(),
1961 first.AsRegisterPairLow<Register>(),
1962 ShifterOperand(second.AsRegisterPairLow<Register>()));
1963 __ adc(out.AsRegisterPairHigh<Register>(),
1964 first.AsRegisterPairHigh<Register>(),
1965 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001966 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001967 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001968
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001969 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00001970 __ vadds(out.AsFpuRegister<SRegister>(),
1971 first.AsFpuRegister<SRegister>(),
1972 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001973 break;
1974
1975 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00001976 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
1977 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
1978 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001979 break;
1980
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001981 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001982 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001983 }
1984}
1985
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001986void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001987 LocationSummary* locations =
1988 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001989 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001990 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001991 locations->SetInAt(0, Location::RequiresRegister());
1992 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001993 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1994 break;
1995 }
1996
1997 case Primitive::kPrimLong: {
1998 locations->SetInAt(0, Location::RequiresRegister());
1999 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002000 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002001 break;
2002 }
Calin Juravle11351682014-10-23 15:38:15 +01002003 case Primitive::kPrimFloat:
2004 case Primitive::kPrimDouble: {
2005 locations->SetInAt(0, Location::RequiresFpuRegister());
2006 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002007 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002008 break;
Calin Juravle11351682014-10-23 15:38:15 +01002009 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002010 default:
Calin Juravle11351682014-10-23 15:38:15 +01002011 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002012 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002013}
2014
2015void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
2016 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01002017 Location out = locations->Out();
2018 Location first = locations->InAt(0);
2019 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002020 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002021 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01002022 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002023 __ sub(out.AsRegister<Register>(),
2024 first.AsRegister<Register>(),
2025 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002026 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002027 __ AddConstant(out.AsRegister<Register>(),
2028 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01002029 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002030 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002031 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002032 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002033
Calin Juravle11351682014-10-23 15:38:15 +01002034 case Primitive::kPrimLong: {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002035 DCHECK(second.IsRegisterPair());
Calin Juravle11351682014-10-23 15:38:15 +01002036 __ subs(out.AsRegisterPairLow<Register>(),
2037 first.AsRegisterPairLow<Register>(),
2038 ShifterOperand(second.AsRegisterPairLow<Register>()));
2039 __ sbc(out.AsRegisterPairHigh<Register>(),
2040 first.AsRegisterPairHigh<Register>(),
2041 ShifterOperand(second.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002042 break;
Calin Juravle11351682014-10-23 15:38:15 +01002043 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002044
Calin Juravle11351682014-10-23 15:38:15 +01002045 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002046 __ vsubs(out.AsFpuRegister<SRegister>(),
2047 first.AsFpuRegister<SRegister>(),
2048 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002049 break;
Calin Juravle11351682014-10-23 15:38:15 +01002050 }
2051
2052 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002053 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2054 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2055 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01002056 break;
2057 }
2058
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002059
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002060 default:
Calin Juravle11351682014-10-23 15:38:15 +01002061 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002062 }
2063}
2064
Calin Juravle34bacdf2014-10-07 20:23:36 +01002065void LocationsBuilderARM::VisitMul(HMul* mul) {
2066 LocationSummary* locations =
2067 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2068 switch (mul->GetResultType()) {
2069 case Primitive::kPrimInt:
2070 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002071 locations->SetInAt(0, Location::RequiresRegister());
2072 locations->SetInAt(1, Location::RequiresRegister());
2073 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002074 break;
2075 }
2076
Calin Juravleb5bfa962014-10-21 18:02:24 +01002077 case Primitive::kPrimFloat:
2078 case Primitive::kPrimDouble: {
2079 locations->SetInAt(0, Location::RequiresFpuRegister());
2080 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002081 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002082 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002083 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002084
2085 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002086 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002087 }
2088}
2089
2090void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
2091 LocationSummary* locations = mul->GetLocations();
2092 Location out = locations->Out();
2093 Location first = locations->InAt(0);
2094 Location second = locations->InAt(1);
2095 switch (mul->GetResultType()) {
2096 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00002097 __ mul(out.AsRegister<Register>(),
2098 first.AsRegister<Register>(),
2099 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002100 break;
2101 }
2102 case Primitive::kPrimLong: {
2103 Register out_hi = out.AsRegisterPairHigh<Register>();
2104 Register out_lo = out.AsRegisterPairLow<Register>();
2105 Register in1_hi = first.AsRegisterPairHigh<Register>();
2106 Register in1_lo = first.AsRegisterPairLow<Register>();
2107 Register in2_hi = second.AsRegisterPairHigh<Register>();
2108 Register in2_lo = second.AsRegisterPairLow<Register>();
2109
2110 // Extra checks to protect caused by the existence of R1_R2.
2111 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
2112 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
2113 DCHECK_NE(out_hi, in1_lo);
2114 DCHECK_NE(out_hi, in2_lo);
2115
2116 // input: in1 - 64 bits, in2 - 64 bits
2117 // output: out
2118 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2119 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2120 // parts: out.lo = (in1.lo * in2.lo)[31:0]
2121
2122 // IP <- in1.lo * in2.hi
2123 __ mul(IP, in1_lo, in2_hi);
2124 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2125 __ mla(out_hi, in1_hi, in2_lo, IP);
2126 // out.lo <- (in1.lo * in2.lo)[31:0];
2127 __ umull(out_lo, IP, in1_lo, in2_lo);
2128 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2129 __ add(out_hi, out_hi, ShifterOperand(IP));
2130 break;
2131 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002132
2133 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002134 __ vmuls(out.AsFpuRegister<SRegister>(),
2135 first.AsFpuRegister<SRegister>(),
2136 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002137 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002138 }
2139
2140 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002141 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2142 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2143 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01002144 break;
2145 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002146
2147 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002148 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002149 }
2150}
2151
Zheng Xuc6667102015-05-15 16:08:45 +08002152void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2153 DCHECK(instruction->IsDiv() || instruction->IsRem());
2154 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2155
2156 LocationSummary* locations = instruction->GetLocations();
2157 Location second = locations->InAt(1);
2158 DCHECK(second.IsConstant());
2159
2160 Register out = locations->Out().AsRegister<Register>();
2161 Register dividend = locations->InAt(0).AsRegister<Register>();
2162 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2163 DCHECK(imm == 1 || imm == -1);
2164
2165 if (instruction->IsRem()) {
2166 __ LoadImmediate(out, 0);
2167 } else {
2168 if (imm == 1) {
2169 __ Mov(out, dividend);
2170 } else {
2171 __ rsb(out, dividend, ShifterOperand(0));
2172 }
2173 }
2174}
2175
2176void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2177 DCHECK(instruction->IsDiv() || instruction->IsRem());
2178 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2179
2180 LocationSummary* locations = instruction->GetLocations();
2181 Location second = locations->InAt(1);
2182 DCHECK(second.IsConstant());
2183
2184 Register out = locations->Out().AsRegister<Register>();
2185 Register dividend = locations->InAt(0).AsRegister<Register>();
2186 Register temp = locations->GetTemp(0).AsRegister<Register>();
2187 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Vladimir Marko80afd022015-05-19 18:08:00 +01002188 uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08002189 DCHECK(IsPowerOfTwo(abs_imm));
2190 int ctz_imm = CTZ(abs_imm);
2191
2192 if (ctz_imm == 1) {
2193 __ Lsr(temp, dividend, 32 - ctz_imm);
2194 } else {
2195 __ Asr(temp, dividend, 31);
2196 __ Lsr(temp, temp, 32 - ctz_imm);
2197 }
2198 __ add(out, temp, ShifterOperand(dividend));
2199
2200 if (instruction->IsDiv()) {
2201 __ Asr(out, out, ctz_imm);
2202 if (imm < 0) {
2203 __ rsb(out, out, ShifterOperand(0));
2204 }
2205 } else {
2206 __ ubfx(out, out, 0, ctz_imm);
2207 __ sub(out, out, ShifterOperand(temp));
2208 }
2209}
2210
2211void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2212 DCHECK(instruction->IsDiv() || instruction->IsRem());
2213 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2214
2215 LocationSummary* locations = instruction->GetLocations();
2216 Location second = locations->InAt(1);
2217 DCHECK(second.IsConstant());
2218
2219 Register out = locations->Out().AsRegister<Register>();
2220 Register dividend = locations->InAt(0).AsRegister<Register>();
2221 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2222 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2223 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2224
2225 int64_t magic;
2226 int shift;
2227 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2228
2229 __ LoadImmediate(temp1, magic);
2230 __ smull(temp2, temp1, dividend, temp1);
2231
2232 if (imm > 0 && magic < 0) {
2233 __ add(temp1, temp1, ShifterOperand(dividend));
2234 } else if (imm < 0 && magic > 0) {
2235 __ sub(temp1, temp1, ShifterOperand(dividend));
2236 }
2237
2238 if (shift != 0) {
2239 __ Asr(temp1, temp1, shift);
2240 }
2241
2242 if (instruction->IsDiv()) {
2243 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
2244 } else {
2245 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
2246 // TODO: Strength reduction for mls.
2247 __ LoadImmediate(temp2, imm);
2248 __ mls(out, temp1, temp2, dividend);
2249 }
2250}
2251
2252void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
2253 DCHECK(instruction->IsDiv() || instruction->IsRem());
2254 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
2255
2256 LocationSummary* locations = instruction->GetLocations();
2257 Location second = locations->InAt(1);
2258 DCHECK(second.IsConstant());
2259
2260 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2261 if (imm == 0) {
2262 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2263 } else if (imm == 1 || imm == -1) {
2264 DivRemOneOrMinusOne(instruction);
2265 } else if (IsPowerOfTwo(std::abs(imm))) {
2266 DivRemByPowerOfTwo(instruction);
2267 } else {
2268 DCHECK(imm <= -2 || imm >= 2);
2269 GenerateDivRemWithAnyConstant(instruction);
2270 }
2271}
2272
Calin Juravle7c4954d2014-10-28 16:57:40 +00002273void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002274 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2275 if (div->GetResultType() == Primitive::kPrimLong) {
2276 // pLdiv runtime call.
2277 call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002278 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
2279 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002280 } else if (div->GetResultType() == Primitive::kPrimInt &&
2281 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
2282 // pIdivmod runtime call.
2283 call_kind = LocationSummary::kCall;
2284 }
2285
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002286 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2287
Calin Juravle7c4954d2014-10-28 16:57:40 +00002288 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002289 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002290 if (div->InputAt(1)->IsConstant()) {
2291 locations->SetInAt(0, Location::RequiresRegister());
2292 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
2293 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2294 int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
2295 if (abs_imm <= 1) {
2296 // No temp register required.
2297 } else {
2298 locations->AddTemp(Location::RequiresRegister());
2299 if (!IsPowerOfTwo(abs_imm)) {
2300 locations->AddTemp(Location::RequiresRegister());
2301 }
2302 }
2303 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002304 locations->SetInAt(0, Location::RequiresRegister());
2305 locations->SetInAt(1, Location::RequiresRegister());
2306 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2307 } else {
2308 InvokeRuntimeCallingConvention calling_convention;
2309 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2310 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2311 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2312 // we only need the former.
2313 locations->SetOut(Location::RegisterLocation(R0));
2314 }
Calin Juravled0d48522014-11-04 16:40:20 +00002315 break;
2316 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002317 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002318 InvokeRuntimeCallingConvention calling_convention;
2319 locations->SetInAt(0, Location::RegisterPairLocation(
2320 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2321 locations->SetInAt(1, Location::RegisterPairLocation(
2322 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002323 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002324 break;
2325 }
2326 case Primitive::kPrimFloat:
2327 case Primitive::kPrimDouble: {
2328 locations->SetInAt(0, Location::RequiresFpuRegister());
2329 locations->SetInAt(1, Location::RequiresFpuRegister());
2330 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2331 break;
2332 }
2333
2334 default:
2335 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2336 }
2337}
2338
2339void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
2340 LocationSummary* locations = div->GetLocations();
2341 Location out = locations->Out();
2342 Location first = locations->InAt(0);
2343 Location second = locations->InAt(1);
2344
2345 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002346 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002347 if (second.IsConstant()) {
2348 GenerateDivRemConstantIntegral(div);
2349 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002350 __ sdiv(out.AsRegister<Register>(),
2351 first.AsRegister<Register>(),
2352 second.AsRegister<Register>());
2353 } else {
2354 InvokeRuntimeCallingConvention calling_convention;
2355 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2356 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2357 DCHECK_EQ(R0, out.AsRegister<Register>());
2358
2359 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr);
2360 }
Calin Juravled0d48522014-11-04 16:40:20 +00002361 break;
2362 }
2363
Calin Juravle7c4954d2014-10-28 16:57:40 +00002364 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002365 InvokeRuntimeCallingConvention calling_convention;
2366 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2367 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2368 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2369 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2370 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002371 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002372
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002373 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002374 break;
2375 }
2376
2377 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00002378 __ vdivs(out.AsFpuRegister<SRegister>(),
2379 first.AsFpuRegister<SRegister>(),
2380 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002381 break;
2382 }
2383
2384 case Primitive::kPrimDouble: {
2385 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2386 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
2387 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
2388 break;
2389 }
2390
2391 default:
2392 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2393 }
2394}
2395
Calin Juravlebacfec32014-11-14 15:54:36 +00002396void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002397 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002398
2399 // Most remainders are implemented in the runtime.
2400 LocationSummary::CallKind call_kind = LocationSummary::kCall;
Zheng Xuc6667102015-05-15 16:08:45 +08002401 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
2402 // sdiv will be replaced by other instruction sequence.
2403 call_kind = LocationSummary::kNoCall;
2404 } else if ((rem->GetResultType() == Primitive::kPrimInt)
2405 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002406 // Have hardware divide instruction for int, do it with three instructions.
2407 call_kind = LocationSummary::kNoCall;
2408 }
2409
Calin Juravlebacfec32014-11-14 15:54:36 +00002410 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2411
Calin Juravled2ec87d2014-12-08 14:24:46 +00002412 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002413 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002414 if (rem->InputAt(1)->IsConstant()) {
2415 locations->SetInAt(0, Location::RequiresRegister());
2416 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
2417 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2418 int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
2419 if (abs_imm <= 1) {
2420 // No temp register required.
2421 } else {
2422 locations->AddTemp(Location::RequiresRegister());
2423 if (!IsPowerOfTwo(abs_imm)) {
2424 locations->AddTemp(Location::RequiresRegister());
2425 }
2426 }
2427 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002428 locations->SetInAt(0, Location::RequiresRegister());
2429 locations->SetInAt(1, Location::RequiresRegister());
2430 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2431 locations->AddTemp(Location::RequiresRegister());
2432 } else {
2433 InvokeRuntimeCallingConvention calling_convention;
2434 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2435 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2436 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
2437 // we only need the latter.
2438 locations->SetOut(Location::RegisterLocation(R1));
2439 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002440 break;
2441 }
2442 case Primitive::kPrimLong: {
2443 InvokeRuntimeCallingConvention calling_convention;
2444 locations->SetInAt(0, Location::RegisterPairLocation(
2445 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2446 locations->SetInAt(1, Location::RegisterPairLocation(
2447 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2448 // The runtime helper puts the output in R2,R3.
2449 locations->SetOut(Location::RegisterPairLocation(R2, R3));
2450 break;
2451 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00002452 case Primitive::kPrimFloat: {
2453 InvokeRuntimeCallingConvention calling_convention;
2454 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2455 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2456 locations->SetOut(Location::FpuRegisterLocation(S0));
2457 break;
2458 }
2459
Calin Juravlebacfec32014-11-14 15:54:36 +00002460 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002461 InvokeRuntimeCallingConvention calling_convention;
2462 locations->SetInAt(0, Location::FpuRegisterPairLocation(
2463 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
2464 locations->SetInAt(1, Location::FpuRegisterPairLocation(
2465 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
2466 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00002467 break;
2468 }
2469
2470 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002471 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002472 }
2473}
2474
2475void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
2476 LocationSummary* locations = rem->GetLocations();
2477 Location out = locations->Out();
2478 Location first = locations->InAt(0);
2479 Location second = locations->InAt(1);
2480
Calin Juravled2ec87d2014-12-08 14:24:46 +00002481 Primitive::Type type = rem->GetResultType();
2482 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002483 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08002484 if (second.IsConstant()) {
2485 GenerateDivRemConstantIntegral(rem);
2486 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002487 Register reg1 = first.AsRegister<Register>();
2488 Register reg2 = second.AsRegister<Register>();
2489 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00002490
Andreas Gampeb51cdb32015-03-29 17:32:48 -07002491 // temp = reg1 / reg2 (integer division)
2492 // temp = temp * reg2
2493 // dest = reg1 - temp
2494 __ sdiv(temp, reg1, reg2);
2495 __ mul(temp, temp, reg2);
2496 __ sub(out.AsRegister<Register>(), reg1, ShifterOperand(temp));
2497 } else {
2498 InvokeRuntimeCallingConvention calling_convention;
2499 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
2500 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
2501 DCHECK_EQ(R1, out.AsRegister<Register>());
2502
2503 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr);
2504 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002505 break;
2506 }
2507
2508 case Primitive::kPrimLong: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002509 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002510 break;
2511 }
2512
Calin Juravled2ec87d2014-12-08 14:24:46 +00002513 case Primitive::kPrimFloat: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002514 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr);
Calin Juravled2ec87d2014-12-08 14:24:46 +00002515 break;
2516 }
2517
Calin Juravlebacfec32014-11-14 15:54:36 +00002518 case Primitive::kPrimDouble: {
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002519 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002520 break;
2521 }
2522
2523 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002524 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002525 }
2526}
2527
Calin Juravled0d48522014-11-04 16:40:20 +00002528void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2529 LocationSummary* locations =
2530 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002531 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00002532 if (instruction->HasUses()) {
2533 locations->SetOut(Location::SameAsFirstInput());
2534 }
2535}
2536
2537void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2538 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
2539 codegen_->AddSlowPath(slow_path);
2540
2541 LocationSummary* locations = instruction->GetLocations();
2542 Location value = locations->InAt(0);
2543
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002544 switch (instruction->GetType()) {
2545 case Primitive::kPrimInt: {
2546 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002547 __ cmp(value.AsRegister<Register>(), ShifterOperand(0));
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002548 __ b(slow_path->GetEntryLabel(), EQ);
2549 } else {
2550 DCHECK(value.IsConstant()) << value;
2551 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2552 __ b(slow_path->GetEntryLabel());
2553 }
2554 }
2555 break;
2556 }
2557 case Primitive::kPrimLong: {
2558 if (value.IsRegisterPair()) {
2559 __ orrs(IP,
2560 value.AsRegisterPairLow<Register>(),
2561 ShifterOperand(value.AsRegisterPairHigh<Register>()));
2562 __ b(slow_path->GetEntryLabel(), EQ);
2563 } else {
2564 DCHECK(value.IsConstant()) << value;
2565 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2566 __ b(slow_path->GetEntryLabel());
2567 }
2568 }
2569 break;
2570 default:
2571 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2572 }
2573 }
Calin Juravled0d48522014-11-04 16:40:20 +00002574}
2575
Calin Juravle9aec02f2014-11-18 23:06:35 +00002576void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
2577 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2578
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002579 LocationSummary* locations =
2580 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002581
2582 switch (op->GetResultType()) {
2583 case Primitive::kPrimInt: {
2584 locations->SetInAt(0, Location::RequiresRegister());
2585 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1)));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002586 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002587 break;
2588 }
2589 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002590 locations->SetInAt(0, Location::RequiresRegister());
2591 locations->SetInAt(1, Location::RequiresRegister());
2592 locations->AddTemp(Location::RequiresRegister());
2593 locations->SetOut(Location::RequiresRegister());
Calin Juravle9aec02f2014-11-18 23:06:35 +00002594 break;
2595 }
2596 default:
2597 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
2598 }
2599}
2600
2601void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
2602 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2603
2604 LocationSummary* locations = op->GetLocations();
2605 Location out = locations->Out();
2606 Location first = locations->InAt(0);
2607 Location second = locations->InAt(1);
2608
2609 Primitive::Type type = op->GetResultType();
2610 switch (type) {
2611 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002612 Register out_reg = out.AsRegister<Register>();
2613 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002614 // Arm doesn't mask the shift count so we need to do it ourselves.
2615 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002616 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002617 __ and_(second_reg, second_reg, ShifterOperand(kMaxIntShiftValue));
2618 if (op->IsShl()) {
2619 __ Lsl(out_reg, first_reg, second_reg);
2620 } else if (op->IsShr()) {
2621 __ Asr(out_reg, first_reg, second_reg);
2622 } else {
2623 __ Lsr(out_reg, first_reg, second_reg);
2624 }
2625 } else {
2626 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
2627 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue);
2628 if (shift_value == 0) { // arm does not support shifting with 0 immediate.
2629 __ Mov(out_reg, first_reg);
2630 } else if (op->IsShl()) {
2631 __ Lsl(out_reg, first_reg, shift_value);
2632 } else if (op->IsShr()) {
2633 __ Asr(out_reg, first_reg, shift_value);
2634 } else {
2635 __ Lsr(out_reg, first_reg, shift_value);
2636 }
2637 }
2638 break;
2639 }
2640 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002641 Register o_h = out.AsRegisterPairHigh<Register>();
2642 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002643
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002644 Register temp = locations->GetTemp(0).AsRegister<Register>();
2645
2646 Register high = first.AsRegisterPairHigh<Register>();
2647 Register low = first.AsRegisterPairLow<Register>();
2648
2649 Register second_reg = second.AsRegister<Register>();
2650
Calin Juravle9aec02f2014-11-18 23:06:35 +00002651 if (op->IsShl()) {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002652 // Shift the high part
2653 __ and_(second_reg, second_reg, ShifterOperand(63));
2654 __ Lsl(o_h, high, second_reg);
2655 // Shift the low part and `or` what overflew on the high part
2656 __ rsb(temp, second_reg, ShifterOperand(32));
2657 __ Lsr(temp, low, temp);
2658 __ orr(o_h, o_h, ShifterOperand(temp));
2659 // If the shift is > 32 bits, override the high part
2660 __ subs(temp, second_reg, ShifterOperand(32));
2661 __ it(PL);
2662 __ Lsl(o_h, low, temp, false, PL);
2663 // Shift the low part
2664 __ Lsl(o_l, low, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002665 } else if (op->IsShr()) {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002666 // Shift the low part
2667 __ and_(second_reg, second_reg, ShifterOperand(63));
2668 __ Lsr(o_l, low, second_reg);
2669 // Shift the high part and `or` what underflew on the low part
2670 __ rsb(temp, second_reg, ShifterOperand(32));
2671 __ Lsl(temp, high, temp);
2672 __ orr(o_l, o_l, ShifterOperand(temp));
2673 // If the shift is > 32 bits, override the low part
2674 __ subs(temp, second_reg, ShifterOperand(32));
2675 __ it(PL);
2676 __ Asr(o_l, high, temp, false, PL);
2677 // Shift the high part
2678 __ Asr(o_h, high, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002679 } else {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00002680 // same as Shr except we use `Lsr`s and not `Asr`s
2681 __ and_(second_reg, second_reg, ShifterOperand(63));
2682 __ Lsr(o_l, low, second_reg);
2683 __ rsb(temp, second_reg, ShifterOperand(32));
2684 __ Lsl(temp, high, temp);
2685 __ orr(o_l, o_l, ShifterOperand(temp));
2686 __ subs(temp, second_reg, ShifterOperand(32));
2687 __ it(PL);
2688 __ Lsr(o_l, high, temp, false, PL);
2689 __ Lsr(o_h, high, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002690 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00002691 break;
2692 }
2693 default:
2694 LOG(FATAL) << "Unexpected operation type " << type;
2695 }
2696}
2697
2698void LocationsBuilderARM::VisitShl(HShl* shl) {
2699 HandleShift(shl);
2700}
2701
2702void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
2703 HandleShift(shl);
2704}
2705
2706void LocationsBuilderARM::VisitShr(HShr* shr) {
2707 HandleShift(shr);
2708}
2709
2710void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
2711 HandleShift(shr);
2712}
2713
2714void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
2715 HandleShift(ushr);
2716}
2717
2718void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
2719 HandleShift(ushr);
2720}
2721
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002722void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002723 LocationSummary* locations =
2724 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002725 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002726 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2727 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2728 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002729}
2730
2731void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
2732 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002733 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002734 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002735 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2736 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002737 instruction->GetDexPc(),
2738 nullptr);
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002739}
2740
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002741void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
2742 LocationSummary* locations =
2743 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2744 InvokeRuntimeCallingConvention calling_convention;
2745 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002746 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002747 locations->SetOut(Location::RegisterLocation(R0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002748 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002749}
2750
2751void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
2752 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002753 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002754 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002755 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
2756 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00002757 instruction->GetDexPc(),
2758 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002759}
2760
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002761void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002762 LocationSummary* locations =
2763 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002764 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2765 if (location.IsStackSlot()) {
2766 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2767 } else if (location.IsDoubleStackSlot()) {
2768 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002769 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002770 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002771}
2772
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01002773void InstructionCodeGeneratorARM::VisitParameterValue(
2774 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002775 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01002776}
2777
2778void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
2779 LocationSummary* locations =
2780 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2781 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
2782}
2783
2784void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
2785 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002786}
2787
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002788void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002789 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002790 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002791 locations->SetInAt(0, Location::RequiresRegister());
2792 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002793}
2794
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002795void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
2796 LocationSummary* locations = not_->GetLocations();
2797 Location out = locations->Out();
2798 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002799 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002800 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002801 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002802 break;
2803
2804 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01002805 __ mvn(out.AsRegisterPairLow<Register>(),
2806 ShifterOperand(in.AsRegisterPairLow<Register>()));
2807 __ mvn(out.AsRegisterPairHigh<Register>(),
2808 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002809 break;
2810
2811 default:
2812 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2813 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002814}
2815
David Brazdil66d126e2015-04-03 16:02:44 +01002816void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
2817 LocationSummary* locations =
2818 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
2819 locations->SetInAt(0, Location::RequiresRegister());
2820 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2821}
2822
2823void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01002824 LocationSummary* locations = bool_not->GetLocations();
2825 Location out = locations->Out();
2826 Location in = locations->InAt(0);
2827 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
2828}
2829
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002830void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002831 LocationSummary* locations =
2832 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002833 switch (compare->InputAt(0)->GetType()) {
2834 case Primitive::kPrimLong: {
2835 locations->SetInAt(0, Location::RequiresRegister());
2836 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00002837 // Output overlaps because it is written before doing the low comparison.
2838 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00002839 break;
2840 }
2841 case Primitive::kPrimFloat:
2842 case Primitive::kPrimDouble: {
2843 locations->SetInAt(0, Location::RequiresFpuRegister());
2844 locations->SetInAt(1, Location::RequiresFpuRegister());
2845 locations->SetOut(Location::RequiresRegister());
2846 break;
2847 }
2848 default:
2849 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2850 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002851}
2852
2853void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002854 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002855 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002856 Location left = locations->InAt(0);
2857 Location right = locations->InAt(1);
2858
Vladimir Markof38caa62015-05-29 15:50:18 +01002859 Label less, greater, done;
Calin Juravleddb7df22014-11-25 20:56:51 +00002860 Primitive::Type type = compare->InputAt(0)->GetType();
2861 switch (type) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002862 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002863 __ cmp(left.AsRegisterPairHigh<Register>(),
2864 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002865 __ b(&less, LT);
2866 __ b(&greater, GT);
Calin Juravleddb7df22014-11-25 20:56:51 +00002867 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags.
2868 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002869 __ cmp(left.AsRegisterPairLow<Register>(),
2870 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Calin Juravleddb7df22014-11-25 20:56:51 +00002871 break;
2872 }
2873 case Primitive::kPrimFloat:
2874 case Primitive::kPrimDouble: {
2875 __ LoadImmediate(out, 0);
2876 if (type == Primitive::kPrimFloat) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002877 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002878 } else {
2879 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
2880 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
2881 }
2882 __ vmstat(); // transfer FP status register to ARM APSR.
2883 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002884 break;
2885 }
2886 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002887 LOG(FATAL) << "Unexpected compare type " << type;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002888 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002889 __ b(&done, EQ);
2890 __ b(&less, CC); // CC is for both: unsigned compare for longs and 'less than' for floats.
2891
2892 __ Bind(&greater);
2893 __ LoadImmediate(out, 1);
2894 __ b(&done);
2895
2896 __ Bind(&less);
2897 __ LoadImmediate(out, -1);
2898
2899 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002900}
2901
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002902void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002903 LocationSummary* locations =
2904 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01002905 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2906 locations->SetInAt(i, Location::Any());
2907 }
2908 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002909}
2910
2911void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002912 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002913 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002914}
2915
Calin Juravle52c48962014-12-16 17:02:57 +00002916void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
2917 // TODO (ported from quick): revisit Arm barrier kinds
Kenny Root1d8199d2015-06-02 11:01:10 -07002918 DmbOptions flavor = DmbOptions::ISH; // quiet c++ warnings
Calin Juravle52c48962014-12-16 17:02:57 +00002919 switch (kind) {
2920 case MemBarrierKind::kAnyStore:
2921 case MemBarrierKind::kLoadAny:
2922 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07002923 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00002924 break;
2925 }
2926 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07002927 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00002928 break;
2929 }
2930 default:
2931 LOG(FATAL) << "Unexpected memory barrier " << kind;
2932 }
Kenny Root1d8199d2015-06-02 11:01:10 -07002933 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00002934}
2935
2936void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
2937 uint32_t offset,
2938 Register out_lo,
2939 Register out_hi) {
2940 if (offset != 0) {
2941 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00002942 __ add(IP, addr, ShifterOperand(out_lo));
2943 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00002944 }
2945 __ ldrexd(out_lo, out_hi, addr);
2946}
2947
2948void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
2949 uint32_t offset,
2950 Register value_lo,
2951 Register value_hi,
2952 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00002953 Register temp2,
2954 HInstruction* instruction) {
Vladimir Markof38caa62015-05-29 15:50:18 +01002955 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00002956 if (offset != 0) {
2957 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00002958 __ add(IP, addr, ShifterOperand(temp1));
2959 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00002960 }
2961 __ Bind(&fail);
2962 // We need a load followed by store. (The address used in a STREX instruction must
2963 // be the same as the address in the most recently executed LDREX instruction.)
2964 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00002965 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002966 __ strexd(temp1, value_lo, value_hi, addr);
2967 __ cmp(temp1, ShifterOperand(0));
2968 __ b(&fail, NE);
2969}
2970
2971void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
2972 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2973
Nicolas Geoffray39468442014-09-02 15:17:15 +01002974 LocationSummary* locations =
2975 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002976 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00002977
Calin Juravle52c48962014-12-16 17:02:57 +00002978 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01002979 if (Primitive::IsFloatingPointType(field_type)) {
2980 locations->SetInAt(1, Location::RequiresFpuRegister());
2981 } else {
2982 locations->SetInAt(1, Location::RequiresRegister());
2983 }
2984
Calin Juravle52c48962014-12-16 17:02:57 +00002985 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00002986 bool generate_volatile = field_info.IsVolatile()
2987 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002988 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002989 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00002990 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
2991 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002992 locations->AddTemp(Location::RequiresRegister());
2993 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00002994 } else if (generate_volatile) {
Calin Juravle52c48962014-12-16 17:02:57 +00002995 // Arm encoding have some additional constraints for ldrexd/strexd:
2996 // - registers need to be consecutive
2997 // - the first register should be even but not R14.
2998 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
2999 // enable Arm encoding.
3000 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3001
3002 locations->AddTemp(Location::RequiresRegister());
3003 locations->AddTemp(Location::RequiresRegister());
3004 if (field_type == Primitive::kPrimDouble) {
3005 // For doubles we need two more registers to copy the value.
3006 locations->AddTemp(Location::RegisterLocation(R2));
3007 locations->AddTemp(Location::RegisterLocation(R3));
3008 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003009 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003010}
3011
Calin Juravle52c48962014-12-16 17:02:57 +00003012void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003013 const FieldInfo& field_info,
3014 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003015 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3016
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003017 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00003018 Register base = locations->InAt(0).AsRegister<Register>();
3019 Location value = locations->InAt(1);
3020
3021 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003022 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003023 Primitive::Type field_type = field_info.GetFieldType();
3024 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3025
3026 if (is_volatile) {
3027 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3028 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003029
3030 switch (field_type) {
3031 case Primitive::kPrimBoolean:
3032 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003033 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003034 break;
3035 }
3036
3037 case Primitive::kPrimShort:
3038 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003039 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003040 break;
3041 }
3042
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003043 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003044 case Primitive::kPrimNot: {
Calin Juravle77520bc2015-01-12 18:45:46 +00003045 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003046 break;
3047 }
3048
3049 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003050 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003051 GenerateWideAtomicStore(base, offset,
3052 value.AsRegisterPairLow<Register>(),
3053 value.AsRegisterPairHigh<Register>(),
3054 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003055 locations->GetTemp(1).AsRegister<Register>(),
3056 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003057 } else {
3058 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003059 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003060 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003061 break;
3062 }
3063
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003064 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003065 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003066 break;
3067 }
3068
3069 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003070 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003071 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003072 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
3073 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
3074
3075 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
3076
3077 GenerateWideAtomicStore(base, offset,
3078 value_reg_lo,
3079 value_reg_hi,
3080 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00003081 locations->GetTemp(3).AsRegister<Register>(),
3082 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003083 } else {
3084 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003085 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003086 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003087 break;
3088 }
3089
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003090 case Primitive::kPrimVoid:
3091 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003092 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003093 }
Calin Juravle52c48962014-12-16 17:02:57 +00003094
Calin Juravle77520bc2015-01-12 18:45:46 +00003095 // Longs and doubles are handled in the switch.
3096 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
3097 codegen_->MaybeRecordImplicitNullCheck(instruction);
3098 }
3099
3100 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3101 Register temp = locations->GetTemp(0).AsRegister<Register>();
3102 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003103 codegen_->MarkGCCard(
3104 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003105 }
3106
Calin Juravle52c48962014-12-16 17:02:57 +00003107 if (is_volatile) {
3108 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3109 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003110}
3111
Calin Juravle52c48962014-12-16 17:02:57 +00003112void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3113 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003114 LocationSummary* locations =
3115 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003116 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003117
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003118 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00003119 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003120 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003121 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong);
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01003122
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003123 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3124 locations->SetOut(Location::RequiresFpuRegister());
3125 } else {
3126 locations->SetOut(Location::RequiresRegister(),
3127 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
3128 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003129 if (volatile_for_double) {
Calin Juravle52c48962014-12-16 17:02:57 +00003130 // Arm encoding have some additional constraints for ldrexd/strexd:
3131 // - registers need to be consecutive
3132 // - the first register should be even but not R14.
3133 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever
3134 // enable Arm encoding.
3135 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
3136 locations->AddTemp(Location::RequiresRegister());
3137 locations->AddTemp(Location::RequiresRegister());
3138 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003139}
3140
Calin Juravle52c48962014-12-16 17:02:57 +00003141void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
3142 const FieldInfo& field_info) {
3143 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003144
Calin Juravle52c48962014-12-16 17:02:57 +00003145 LocationSummary* locations = instruction->GetLocations();
3146 Register base = locations->InAt(0).AsRegister<Register>();
3147 Location out = locations->Out();
3148 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003149 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00003150 Primitive::Type field_type = field_info.GetFieldType();
3151 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3152
3153 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003154 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003155 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003156 break;
3157 }
3158
3159 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003160 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003161 break;
3162 }
3163
3164 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003165 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003166 break;
3167 }
3168
3169 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003170 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003171 break;
3172 }
3173
3174 case Primitive::kPrimInt:
3175 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003176 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003177 break;
3178 }
3179
3180 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00003181 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003182 GenerateWideAtomicLoad(base, offset,
3183 out.AsRegisterPairLow<Register>(),
3184 out.AsRegisterPairHigh<Register>());
3185 } else {
3186 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
3187 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003188 break;
3189 }
3190
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003191 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003192 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003193 break;
3194 }
3195
3196 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003197 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00003198 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00003199 Register lo = locations->GetTemp(0).AsRegister<Register>();
3200 Register hi = locations->GetTemp(1).AsRegister<Register>();
3201 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00003202 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003203 __ vmovdrr(out_reg, lo, hi);
3204 } else {
3205 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003206 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003207 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003208 break;
3209 }
3210
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003211 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003212 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003213 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003214 }
Calin Juravle52c48962014-12-16 17:02:57 +00003215
Calin Juravle77520bc2015-01-12 18:45:46 +00003216 // Doubles are handled in the switch.
3217 if (field_type != Primitive::kPrimDouble) {
3218 codegen_->MaybeRecordImplicitNullCheck(instruction);
3219 }
3220
Calin Juravle52c48962014-12-16 17:02:57 +00003221 if (is_volatile) {
3222 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3223 }
3224}
3225
3226void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3227 HandleFieldSet(instruction, instruction->GetFieldInfo());
3228}
3229
3230void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003231 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003232}
3233
3234void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3235 HandleFieldGet(instruction, instruction->GetFieldInfo());
3236}
3237
3238void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3239 HandleFieldGet(instruction, instruction->GetFieldInfo());
3240}
3241
3242void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3243 HandleFieldGet(instruction, instruction->GetFieldInfo());
3244}
3245
3246void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3247 HandleFieldGet(instruction, instruction->GetFieldInfo());
3248}
3249
3250void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3251 HandleFieldSet(instruction, instruction->GetFieldInfo());
3252}
3253
3254void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003255 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003256}
3257
3258void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003259 LocationSummary* locations =
3260 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravle77520bc2015-01-12 18:45:46 +00003261 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003262 if (instruction->HasUses()) {
3263 locations->SetOut(Location::SameAsFirstInput());
3264 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003265}
3266
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003267void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003268 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3269 return;
3270 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003271 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003272
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003273 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
3274 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3275}
3276
3277void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003278 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003279 codegen_->AddSlowPath(slow_path);
3280
3281 LocationSummary* locations = instruction->GetLocations();
3282 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003283
Calin Juravle77520bc2015-01-12 18:45:46 +00003284 __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
3285 __ b(slow_path->GetEntryLabel(), EQ);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003286}
3287
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003288void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
3289 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3290 GenerateImplicitNullCheck(instruction);
3291 } else {
3292 GenerateExplicitNullCheck(instruction);
3293 }
3294}
3295
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003296void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003297 LocationSummary* locations =
3298 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003299 locations->SetInAt(0, Location::RequiresRegister());
3300 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003301 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3302 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3303 } else {
3304 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3305 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003306}
3307
3308void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
3309 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003310 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003311 Location index = locations->InAt(1);
3312
3313 switch (instruction->GetType()) {
3314 case Primitive::kPrimBoolean: {
3315 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003316 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003317 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003318 size_t offset =
3319 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003320 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
3321 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003322 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003323 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
3324 }
3325 break;
3326 }
3327
3328 case Primitive::kPrimByte: {
3329 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003330 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003331 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003332 size_t offset =
3333 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003334 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
3335 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003336 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003337 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
3338 }
3339 break;
3340 }
3341
3342 case Primitive::kPrimShort: {
3343 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003344 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003345 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003346 size_t offset =
3347 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003348 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
3349 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003350 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003351 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
3352 }
3353 break;
3354 }
3355
3356 case Primitive::kPrimChar: {
3357 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003358 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003359 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003360 size_t offset =
3361 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003362 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
3363 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003364 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003365 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
3366 }
3367 break;
3368 }
3369
3370 case Primitive::kPrimInt:
3371 case Primitive::kPrimNot: {
3372 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
3373 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003374 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003375 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003376 size_t offset =
3377 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003378 __ LoadFromOffset(kLoadWord, out, obj, offset);
3379 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003380 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003381 __ LoadFromOffset(kLoadWord, out, IP, data_offset);
3382 }
3383 break;
3384 }
3385
3386 case Primitive::kPrimLong: {
3387 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003388 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003389 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003390 size_t offset =
3391 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003392 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003393 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003394 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003395 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003396 }
3397 break;
3398 }
3399
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003400 case Primitive::kPrimFloat: {
3401 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3402 Location out = locations->Out();
3403 DCHECK(out.IsFpuRegister());
3404 if (index.IsConstant()) {
3405 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3406 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset);
3407 } else {
3408 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3409 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset);
3410 }
3411 break;
3412 }
3413
3414 case Primitive::kPrimDouble: {
3415 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3416 Location out = locations->Out();
3417 DCHECK(out.IsFpuRegisterPair());
3418 if (index.IsConstant()) {
3419 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3420 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3421 } else {
3422 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3423 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3424 }
3425 break;
3426 }
3427
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003428 case Primitive::kPrimVoid:
3429 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003430 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003431 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003432 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003433}
3434
3435void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003436 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003437
3438 bool needs_write_barrier =
3439 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3440 bool needs_runtime_call = instruction->NeedsTypeCheck();
3441
Nicolas Geoffray39468442014-09-02 15:17:15 +01003442 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003443 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
3444 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003445 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003446 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3447 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3448 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003449 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003450 locations->SetInAt(0, Location::RequiresRegister());
3451 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003452 if (Primitive::IsFloatingPointType(value_type)) {
3453 locations->SetInAt(2, Location::RequiresFpuRegister());
3454 } else {
3455 locations->SetInAt(2, Location::RequiresRegister());
3456 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003457
3458 if (needs_write_barrier) {
3459 // Temporary registers for the write barrier.
3460 locations->AddTemp(Location::RequiresRegister());
3461 locations->AddTemp(Location::RequiresRegister());
3462 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003463 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003464}
3465
3466void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
3467 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003468 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003469 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003470 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003471 bool needs_runtime_call = locations->WillCall();
3472 bool needs_write_barrier =
3473 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003474
3475 switch (value_type) {
3476 case Primitive::kPrimBoolean:
3477 case Primitive::kPrimByte: {
3478 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003479 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003480 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003481 size_t offset =
3482 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003483 __ StoreToOffset(kStoreByte, value, obj, offset);
3484 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003485 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003486 __ StoreToOffset(kStoreByte, value, IP, data_offset);
3487 }
3488 break;
3489 }
3490
3491 case Primitive::kPrimShort:
3492 case Primitive::kPrimChar: {
3493 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003494 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003495 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003496 size_t offset =
3497 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003498 __ StoreToOffset(kStoreHalfword, value, obj, offset);
3499 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003500 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003501 __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
3502 }
3503 break;
3504 }
3505
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003506 case Primitive::kPrimInt:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003507 case Primitive::kPrimNot: {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003508 if (!needs_runtime_call) {
3509 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003510 Register value = locations->InAt(2).AsRegister<Register>();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003511 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003512 size_t offset =
3513 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003514 __ StoreToOffset(kStoreWord, value, obj, offset);
3515 } else {
3516 DCHECK(index.IsRegister()) << index;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003517 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003518 __ StoreToOffset(kStoreWord, value, IP, data_offset);
3519 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003520 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003521 if (needs_write_barrier) {
3522 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003523 Register temp = locations->GetTemp(0).AsRegister<Register>();
3524 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003525 codegen_->MarkGCCard(temp, card, obj, value, instruction->GetValueCanBeNull());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003526 }
3527 } else {
3528 DCHECK_EQ(value_type, Primitive::kPrimNot);
Roland Levillain199f3362014-11-27 17:15:16 +00003529 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
3530 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00003531 instruction->GetDexPc(),
3532 nullptr);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003533 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003534 break;
3535 }
3536
3537 case Primitive::kPrimLong: {
3538 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003539 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003540 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003541 size_t offset =
3542 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003543 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003544 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003545 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003546 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003547 }
3548 break;
3549 }
3550
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003551 case Primitive::kPrimFloat: {
3552 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3553 Location value = locations->InAt(2);
3554 DCHECK(value.IsFpuRegister());
3555 if (index.IsConstant()) {
3556 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3557 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset);
3558 } else {
3559 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
3560 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
3561 }
3562 break;
3563 }
3564
3565 case Primitive::kPrimDouble: {
3566 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3567 Location value = locations->InAt(2);
3568 DCHECK(value.IsFpuRegisterPair());
3569 if (index.IsConstant()) {
3570 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3571 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset);
3572 } else {
3573 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
3574 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
3575 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003576
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003577 break;
3578 }
3579
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003580 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003581 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003582 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003583 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003584
3585 // Ints and objects are handled in the switch.
3586 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
3587 codegen_->MaybeRecordImplicitNullCheck(instruction);
3588 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003589}
3590
3591void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003592 LocationSummary* locations =
3593 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003594 locations->SetInAt(0, Location::RequiresRegister());
3595 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003596}
3597
3598void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
3599 LocationSummary* locations = instruction->GetLocations();
3600 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003601 Register obj = locations->InAt(0).AsRegister<Register>();
3602 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003603 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00003604 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003605}
3606
3607void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003608 LocationSummary* locations =
3609 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003610 locations->SetInAt(0, Location::RequiresRegister());
3611 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003612 if (instruction->HasUses()) {
3613 locations->SetOut(Location::SameAsFirstInput());
3614 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003615}
3616
3617void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
3618 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003619 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
Nicolas Geoffray39468442014-09-02 15:17:15 +01003620 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003621 codegen_->AddSlowPath(slow_path);
3622
Roland Levillain271ab9c2014-11-27 15:23:57 +00003623 Register index = locations->InAt(0).AsRegister<Register>();
3624 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003625
3626 __ cmp(index, ShifterOperand(length));
3627 __ b(slow_path->GetEntryLabel(), CS);
3628}
3629
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003630void CodeGeneratorARM::MarkGCCard(Register temp,
3631 Register card,
3632 Register object,
3633 Register value,
3634 bool can_be_null) {
Vladimir Markof38caa62015-05-29 15:50:18 +01003635 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003636 if (can_be_null) {
3637 __ CompareAndBranchIfZero(value, &is_null);
3638 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003639 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
3640 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
3641 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003642 if (can_be_null) {
3643 __ Bind(&is_null);
3644 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003645}
3646
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003647void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
3648 temp->SetLocations(nullptr);
3649}
3650
3651void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) {
3652 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003653 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003654}
3655
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003656void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003657 UNUSED(instruction);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003658 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003659}
3660
3661void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003662 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3663}
3664
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003665void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
3666 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3667}
3668
3669void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003670 HBasicBlock* block = instruction->GetBlock();
3671 if (block->GetLoopInformation() != nullptr) {
3672 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3673 // The back edge will generate the suspend check.
3674 return;
3675 }
3676 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3677 // The goto will generate the suspend check.
3678 return;
3679 }
3680 GenerateSuspendCheck(instruction, nullptr);
3681}
3682
3683void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
3684 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003685 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01003686 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
3687 if (slow_path == nullptr) {
3688 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
3689 instruction->SetSlowPath(slow_path);
3690 codegen_->AddSlowPath(slow_path);
3691 if (successor != nullptr) {
3692 DCHECK(successor->IsLoopHeader());
3693 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
3694 }
3695 } else {
3696 DCHECK_EQ(slow_path->GetSuccessor(), successor);
3697 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003698
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003699 __ LoadFromOffset(
3700 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
3701 __ cmp(IP, ShifterOperand(0));
3702 // TODO: Figure out the branch offsets and use cbz/cbnz.
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003703 if (successor == nullptr) {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003704 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003705 __ Bind(slow_path->GetReturnLabel());
3706 } else {
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00003707 __ b(codegen_->GetLabelOf(successor), EQ);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003708 __ b(slow_path->GetEntryLabel());
3709 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003710}
3711
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003712ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
3713 return codegen_->GetAssembler();
3714}
3715
3716void ParallelMoveResolverARM::EmitMove(size_t index) {
3717 MoveOperands* move = moves_.Get(index);
3718 Location source = move->GetSource();
3719 Location destination = move->GetDestination();
3720
3721 if (source.IsRegister()) {
3722 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003723 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003724 } else {
3725 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003726 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003727 SP, destination.GetStackIndex());
3728 }
3729 } else if (source.IsStackSlot()) {
3730 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003731 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003732 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003733 } else if (destination.IsFpuRegister()) {
3734 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003735 } else {
3736 DCHECK(destination.IsStackSlot());
3737 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
3738 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3739 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003740 } else if (source.IsFpuRegister()) {
3741 if (destination.IsFpuRegister()) {
3742 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003743 } else {
3744 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003745 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
3746 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003747 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003748 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003749 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
3750 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003751 } else if (destination.IsRegisterPair()) {
3752 DCHECK(ExpectedPairLayout(destination));
3753 __ LoadFromOffset(
3754 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
3755 } else {
3756 DCHECK(destination.IsFpuRegisterPair()) << destination;
3757 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
3758 SP,
3759 source.GetStackIndex());
3760 }
3761 } else if (source.IsRegisterPair()) {
3762 if (destination.IsRegisterPair()) {
3763 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
3764 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
3765 } else {
3766 DCHECK(destination.IsDoubleStackSlot()) << destination;
3767 DCHECK(ExpectedPairLayout(source));
3768 __ StoreToOffset(
3769 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
3770 }
3771 } else if (source.IsFpuRegisterPair()) {
3772 if (destination.IsFpuRegisterPair()) {
3773 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
3774 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
3775 } else {
3776 DCHECK(destination.IsDoubleStackSlot()) << destination;
3777 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
3778 SP,
3779 destination.GetStackIndex());
3780 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003781 } else {
3782 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003783 HConstant* constant = source.GetConstant();
3784 if (constant->IsIntConstant() || constant->IsNullConstant()) {
3785 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003786 if (destination.IsRegister()) {
3787 __ LoadImmediate(destination.AsRegister<Register>(), value);
3788 } else {
3789 DCHECK(destination.IsStackSlot());
3790 __ LoadImmediate(IP, value);
3791 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3792 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003793 } else if (constant->IsLongConstant()) {
3794 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003795 if (destination.IsRegisterPair()) {
3796 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
3797 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003798 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003799 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003800 __ LoadImmediate(IP, Low32Bits(value));
3801 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3802 __ LoadImmediate(IP, High32Bits(value));
3803 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3804 }
3805 } else if (constant->IsDoubleConstant()) {
3806 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003807 if (destination.IsFpuRegisterPair()) {
3808 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003809 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003810 DCHECK(destination.IsDoubleStackSlot()) << destination;
3811 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003812 __ LoadImmediate(IP, Low32Bits(int_value));
3813 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3814 __ LoadImmediate(IP, High32Bits(int_value));
3815 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
3816 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003817 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003818 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003819 float value = constant->AsFloatConstant()->GetValue();
3820 if (destination.IsFpuRegister()) {
3821 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
3822 } else {
3823 DCHECK(destination.IsStackSlot());
3824 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
3825 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
3826 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003827 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003828 }
3829}
3830
3831void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
3832 __ Mov(IP, reg);
3833 __ LoadFromOffset(kLoadWord, reg, SP, mem);
3834 __ StoreToOffset(kStoreWord, IP, SP, mem);
3835}
3836
3837void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
3838 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
3839 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
3840 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
3841 SP, mem1 + stack_offset);
3842 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
3843 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
3844 SP, mem2 + stack_offset);
3845 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
3846}
3847
3848void ParallelMoveResolverARM::EmitSwap(size_t index) {
3849 MoveOperands* move = moves_.Get(index);
3850 Location source = move->GetSource();
3851 Location destination = move->GetDestination();
3852
3853 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003854 DCHECK_NE(source.AsRegister<Register>(), IP);
3855 DCHECK_NE(destination.AsRegister<Register>(), IP);
3856 __ Mov(IP, source.AsRegister<Register>());
3857 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
3858 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003859 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003860 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003861 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003862 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003863 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3864 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003865 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003866 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003867 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003868 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003869 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003870 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003871 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003872 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003873 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
3874 destination.AsRegisterPairHigh<Register>(),
3875 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003876 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003877 Register low_reg = source.IsRegisterPair()
3878 ? source.AsRegisterPairLow<Register>()
3879 : destination.AsRegisterPairLow<Register>();
3880 int mem = source.IsRegisterPair()
3881 ? destination.GetStackIndex()
3882 : source.GetStackIndex();
3883 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003884 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003885 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003886 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003887 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003888 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
3889 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003890 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003891 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003892 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003893 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
3894 DRegister reg = source.IsFpuRegisterPair()
3895 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
3896 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
3897 int mem = source.IsFpuRegisterPair()
3898 ? destination.GetStackIndex()
3899 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003900 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003901 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00003902 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00003903 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
3904 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
3905 : destination.AsFpuRegister<SRegister>();
3906 int mem = source.IsFpuRegister()
3907 ? destination.GetStackIndex()
3908 : source.GetStackIndex();
3909
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003910 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00003911 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00003912 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003913 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003914 Exchange(source.GetStackIndex(), destination.GetStackIndex());
3915 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003916 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00003917 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003918 }
3919}
3920
3921void ParallelMoveResolverARM::SpillScratch(int reg) {
3922 __ Push(static_cast<Register>(reg));
3923}
3924
3925void ParallelMoveResolverARM::RestoreScratch(int reg) {
3926 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003927}
3928
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003929void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003930 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3931 ? LocationSummary::kCallOnSlowPath
3932 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003933 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003934 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003935 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003936 locations->SetOut(Location::RequiresRegister());
3937}
3938
3939void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003940 LocationSummary* locations = cls->GetLocations();
3941 Register out = locations->Out().AsRegister<Register>();
3942 Register current_method = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003943 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003944 DCHECK(!cls->CanCallRuntime());
3945 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003946 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07003947 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003948 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003949 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003950 __ LoadFromOffset(kLoadWord,
3951 out,
3952 current_method,
Mathieu Chartiere401d142015-04-22 13:56:20 -07003953 ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003954 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003955
3956 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3957 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3958 codegen_->AddSlowPath(slow_path);
3959 __ cmp(out, ShifterOperand(0));
3960 __ b(slow_path->GetEntryLabel(), EQ);
3961 if (cls->MustGenerateClinitCheck()) {
3962 GenerateClassInitializationCheck(slow_path, out);
3963 } else {
3964 __ Bind(slow_path->GetExitLabel());
3965 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003966 }
3967}
3968
3969void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
3970 LocationSummary* locations =
3971 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3972 locations->SetInAt(0, Location::RequiresRegister());
3973 if (check->HasUses()) {
3974 locations->SetOut(Location::SameAsFirstInput());
3975 }
3976}
3977
3978void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003979 // We assume the class is not null.
3980 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
3981 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003982 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003983 GenerateClassInitializationCheck(slow_path,
3984 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003985}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003986
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003987void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
3988 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003989 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
3990 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
3991 __ b(slow_path->GetEntryLabel(), LT);
3992 // Even if the initialized flag is set, we may be in a situation where caches are not synced
3993 // properly. Therefore, we do a memory fence.
3994 __ dmb(ISH);
3995 __ Bind(slow_path->GetExitLabel());
3996}
3997
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003998void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
3999 LocationSummary* locations =
4000 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004001 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004002 locations->SetOut(Location::RequiresRegister());
4003}
4004
4005void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
4006 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
4007 codegen_->AddSlowPath(slow_path);
4008
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004009 LocationSummary* locations = load->GetLocations();
4010 Register out = locations->Out().AsRegister<Register>();
4011 Register current_method = locations->InAt(0).AsRegister<Register>();
4012 __ LoadFromOffset(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004013 kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
Mathieu Chartiereace4582014-11-24 18:29:54 -08004014 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004015 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
4016 __ cmp(out, ShifterOperand(0));
4017 __ b(slow_path->GetEntryLabel(), EQ);
4018 __ Bind(slow_path->GetExitLabel());
4019}
4020
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004021void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
4022 LocationSummary* locations =
4023 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4024 locations->SetOut(Location::RequiresRegister());
4025}
4026
4027void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004028 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004029 int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
4030 __ LoadFromOffset(kLoadWord, out, TR, offset);
4031 __ LoadImmediate(IP, 0);
4032 __ StoreToOffset(kStoreWord, IP, TR, offset);
4033}
4034
4035void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
4036 LocationSummary* locations =
4037 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4038 InvokeRuntimeCallingConvention calling_convention;
4039 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4040}
4041
4042void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
4043 codegen_->InvokeRuntime(
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004044 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004045}
4046
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004047void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004048 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4049 ? LocationSummary::kNoCall
4050 : LocationSummary::kCallOnSlowPath;
4051 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4052 locations->SetInAt(0, Location::RequiresRegister());
4053 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004054 // The out register is used as a temporary, so it overlaps with the inputs.
4055 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004056}
4057
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004058void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004059 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004060 Register obj = locations->InAt(0).AsRegister<Register>();
4061 Register cls = locations->InAt(1).AsRegister<Register>();
4062 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004063 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Vladimir Markof38caa62015-05-29 15:50:18 +01004064 Label done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004065 SlowPathCodeARM* slow_path = nullptr;
4066
4067 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004068 // avoid null check if we know obj is not null.
4069 if (instruction->MustDoNullCheck()) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00004070 __ CompareAndBranchIfZero(obj, &zero);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004071 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004072 // Compare the class of `obj` with `cls`.
4073 __ LoadFromOffset(kLoadWord, out, obj, class_offset);
4074 __ cmp(out, ShifterOperand(cls));
4075 if (instruction->IsClassFinal()) {
4076 // Classes must be equal for the instanceof to succeed.
4077 __ b(&zero, NE);
4078 __ LoadImmediate(out, 1);
4079 __ b(&done);
4080 } else {
4081 // If the classes are not equal, we go into a slow path.
4082 DCHECK(locations->OnlyCallsOnSlowPath());
4083 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004084 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004085 codegen_->AddSlowPath(slow_path);
4086 __ b(slow_path->GetEntryLabel(), NE);
4087 __ LoadImmediate(out, 1);
4088 __ b(&done);
4089 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004090
4091 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4092 __ Bind(&zero);
4093 __ LoadImmediate(out, 0);
4094 }
4095
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004096 if (slow_path != nullptr) {
4097 __ Bind(slow_path->GetExitLabel());
4098 }
4099 __ Bind(&done);
4100}
4101
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004102void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
4103 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4104 instruction, LocationSummary::kCallOnSlowPath);
4105 locations->SetInAt(0, Location::RequiresRegister());
4106 locations->SetInAt(1, Location::RequiresRegister());
4107 locations->AddTemp(Location::RequiresRegister());
4108}
4109
4110void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
4111 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004112 Register obj = locations->InAt(0).AsRegister<Register>();
4113 Register cls = locations->InAt(1).AsRegister<Register>();
4114 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004115 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4116
4117 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(
4118 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4119 codegen_->AddSlowPath(slow_path);
4120
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004121 // avoid null check if we know obj is not null.
4122 if (instruction->MustDoNullCheck()) {
Vladimir Markof38caa62015-05-29 15:50:18 +01004123 __ CompareAndBranchIfZero(obj, slow_path->GetExitLabel());
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004124 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004125 // Compare the class of `obj` with `cls`.
4126 __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
4127 __ cmp(temp, ShifterOperand(cls));
4128 __ b(slow_path->GetEntryLabel(), NE);
4129 __ Bind(slow_path->GetExitLabel());
4130}
4131
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004132void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4133 LocationSummary* locations =
4134 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4135 InvokeRuntimeCallingConvention calling_convention;
4136 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4137}
4138
4139void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
4140 codegen_->InvokeRuntime(instruction->IsEnter()
4141 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
4142 instruction,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +00004143 instruction->GetDexPc(),
4144 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004145}
4146
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004147void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4148void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4149void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4150
4151void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4152 LocationSummary* locations =
4153 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4154 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4155 || instruction->GetResultType() == Primitive::kPrimLong);
4156 locations->SetInAt(0, Location::RequiresRegister());
4157 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004158 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004159}
4160
4161void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
4162 HandleBitwiseOperation(instruction);
4163}
4164
4165void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
4166 HandleBitwiseOperation(instruction);
4167}
4168
4169void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
4170 HandleBitwiseOperation(instruction);
4171}
4172
4173void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
4174 LocationSummary* locations = instruction->GetLocations();
4175
4176 if (instruction->GetResultType() == Primitive::kPrimInt) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004177 Register first = locations->InAt(0).AsRegister<Register>();
4178 Register second = locations->InAt(1).AsRegister<Register>();
4179 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004180 if (instruction->IsAnd()) {
4181 __ and_(out, first, ShifterOperand(second));
4182 } else if (instruction->IsOr()) {
4183 __ orr(out, first, ShifterOperand(second));
4184 } else {
4185 DCHECK(instruction->IsXor());
4186 __ eor(out, first, ShifterOperand(second));
4187 }
4188 } else {
4189 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4190 Location first = locations->InAt(0);
4191 Location second = locations->InAt(1);
4192 Location out = locations->Out();
4193 if (instruction->IsAnd()) {
4194 __ and_(out.AsRegisterPairLow<Register>(),
4195 first.AsRegisterPairLow<Register>(),
4196 ShifterOperand(second.AsRegisterPairLow<Register>()));
4197 __ and_(out.AsRegisterPairHigh<Register>(),
4198 first.AsRegisterPairHigh<Register>(),
4199 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4200 } else if (instruction->IsOr()) {
4201 __ orr(out.AsRegisterPairLow<Register>(),
4202 first.AsRegisterPairLow<Register>(),
4203 ShifterOperand(second.AsRegisterPairLow<Register>()));
4204 __ orr(out.AsRegisterPairHigh<Register>(),
4205 first.AsRegisterPairHigh<Register>(),
4206 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4207 } else {
4208 DCHECK(instruction->IsXor());
4209 __ eor(out.AsRegisterPairLow<Register>(),
4210 first.AsRegisterPairLow<Register>(),
4211 ShifterOperand(second.AsRegisterPairLow<Register>()));
4212 __ eor(out.AsRegisterPairHigh<Register>(),
4213 first.AsRegisterPairHigh<Register>(),
4214 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4215 }
4216 }
4217}
4218
Nicolas Geoffrayc345f142015-06-04 17:17:32 +00004219void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) {
4220 DCHECK_EQ(temp, kArtMethodRegister);
4221
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004222 // TODO: Implement all kinds of calls:
4223 // 1) boot -> boot
4224 // 2) app -> boot
4225 // 3) app -> app
4226 //
4227 // Currently we implement the app -> app logic, which looks up in the resolve cache.
4228
Jeff Hao848f70a2014-01-15 13:49:50 -08004229 if (invoke->IsStringInit()) {
4230 // temp = thread->string_init_entrypoint
Nicolas Geoffrayc345f142015-06-04 17:17:32 +00004231 __ LoadFromOffset(kLoadWord, temp, TR, invoke->GetStringInitOffset());
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004232 // LR = temp[offset_of_quick_compiled_code]
Nicolas Geoffrayc345f142015-06-04 17:17:32 +00004233 __ LoadFromOffset(kLoadWord, LR, temp,
Mathieu Chartiere401d142015-04-22 13:56:20 -07004234 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004235 kArmWordSize).Int32Value());
4236 // LR()
4237 __ blx(LR);
4238 } else {
Nicolas Geoffrayc345f142015-06-04 17:17:32 +00004239 // temp = method;
4240 LoadCurrentMethod(temp);
4241 if (!invoke->IsRecursive()) {
4242 // temp = temp->dex_cache_resolved_methods_;
4243 __ LoadFromOffset(
4244 kLoadWord, temp, temp, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
4245 // temp = temp[index_in_cache]
4246 __ LoadFromOffset(
4247 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()));
4248 // LR = temp[offset_of_quick_compiled_code]
4249 __ LoadFromOffset(kLoadWord, LR, temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
4250 kArmWordSize).Int32Value());
4251 // LR()
4252 __ blx(LR);
4253 } else {
4254 __ bl(GetFrameEntryLabel());
4255 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004256 }
4257
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08004258 DCHECK(!IsLeafMethod());
4259}
4260
Calin Juravleb1498f62015-02-16 13:13:29 +00004261void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) {
4262 // Nothing to do, this should be removed during prepare for register allocator.
4263 UNUSED(instruction);
4264 LOG(FATAL) << "Unreachable";
4265}
4266
4267void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) {
4268 // Nothing to do, this should be removed during prepare for register allocator.
4269 UNUSED(instruction);
4270 LOG(FATAL) << "Unreachable";
4271}
4272
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004273} // namespace arm
4274} // namespace art