blob: b048c07b4cc7ac36be8cfff1b40b5726be02ddec [file] [log] [blame]
Alexandre Rames5319def2014-10-23 10:03:10 +01001/*
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_arm64.h"
18
19#include "entrypoints/quick/quick_entrypoints.h"
20#include "gc/accounting/card_table.h"
21#include "mirror/array-inl.h"
22#include "mirror/art_method.h"
23#include "mirror/class.h"
24#include "thread.h"
25#include "utils/arm64/assembler_arm64.h"
26#include "utils/assembler.h"
27#include "utils/stack_checks.h"
28
29
30using namespace vixl; // NOLINT(build/namespaces)
31
32#ifdef __
33#error "ARM64 Codegen VIXL macro-assembler macro already defined."
34#endif
35
36
37namespace art {
38
39namespace arm64 {
40
Serban Constantinescu02164b32014-11-13 14:05:07 +000041static constexpr bool kExplicitStackOverflowCheck = false;
Alexandre Rames5319def2014-10-23 10:03:10 +010042static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>);
43static constexpr int kCurrentMethodStackOffset = 0;
44
45namespace {
Alexandre Ramesa89086e2014-11-07 17:13:25 +000046
47bool IsFPType(Primitive::Type type) {
48 return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble;
49}
50
Alexandre Rames67555f72014-11-18 10:55:16 +000051bool IsIntegralType(Primitive::Type type) {
52 switch (type) {
53 case Primitive::kPrimByte:
54 case Primitive::kPrimChar:
55 case Primitive::kPrimShort:
56 case Primitive::kPrimInt:
57 case Primitive::kPrimLong:
58 return true;
59 default:
60 return false;
61 }
62}
63
Alexandre Ramesa89086e2014-11-07 17:13:25 +000064bool Is64BitType(Primitive::Type type) {
65 return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
66}
67
Alexandre Rames5319def2014-10-23 10:03:10 +010068// Convenience helpers to ease conversion to and from VIXL operands.
Alexandre Rames67555f72014-11-18 10:55:16 +000069static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32),
70 "Unexpected values for register codes.");
Alexandre Rames5319def2014-10-23 10:03:10 +010071
72int VIXLRegCodeFromART(int code) {
Alexandre Rames5319def2014-10-23 10:03:10 +010073 if (code == SP) {
74 return vixl::kSPRegInternalCode;
75 }
76 if (code == XZR) {
77 return vixl::kZeroRegCode;
78 }
79 return code;
80}
81
82int ARTRegCodeFromVIXL(int code) {
Alexandre Rames5319def2014-10-23 10:03:10 +010083 if (code == vixl::kSPRegInternalCode) {
84 return SP;
85 }
86 if (code == vixl::kZeroRegCode) {
87 return XZR;
88 }
89 return code;
90}
91
92Register XRegisterFrom(Location location) {
Alexandre Rames3e69f162014-12-10 10:36:50 +000093 DCHECK(location.IsRegister());
Alexandre Rames5319def2014-10-23 10:03:10 +010094 return Register::XRegFromCode(VIXLRegCodeFromART(location.reg()));
95}
96
97Register WRegisterFrom(Location location) {
Alexandre Rames3e69f162014-12-10 10:36:50 +000098 DCHECK(location.IsRegister());
Alexandre Rames5319def2014-10-23 10:03:10 +010099 return Register::WRegFromCode(VIXLRegCodeFromART(location.reg()));
100}
101
102Register RegisterFrom(Location location, Primitive::Type type) {
103 DCHECK(type != Primitive::kPrimVoid && !IsFPType(type));
104 return type == Primitive::kPrimLong ? XRegisterFrom(location) : WRegisterFrom(location);
105}
106
107Register OutputRegister(HInstruction* instr) {
108 return RegisterFrom(instr->GetLocations()->Out(), instr->GetType());
109}
110
111Register InputRegisterAt(HInstruction* instr, int input_index) {
112 return RegisterFrom(instr->GetLocations()->InAt(input_index),
113 instr->InputAt(input_index)->GetType());
114}
115
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000116FPRegister DRegisterFrom(Location location) {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000117 DCHECK(location.IsFpuRegister());
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000118 return FPRegister::DRegFromCode(location.reg());
119}
120
121FPRegister SRegisterFrom(Location location) {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000122 DCHECK(location.IsFpuRegister());
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000123 return FPRegister::SRegFromCode(location.reg());
124}
125
126FPRegister FPRegisterFrom(Location location, Primitive::Type type) {
127 DCHECK(IsFPType(type));
128 return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location);
129}
130
131FPRegister OutputFPRegister(HInstruction* instr) {
132 return FPRegisterFrom(instr->GetLocations()->Out(), instr->GetType());
133}
134
135FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) {
136 return FPRegisterFrom(instr->GetLocations()->InAt(input_index),
137 instr->InputAt(input_index)->GetType());
138}
139
Alexandre Rames3e69f162014-12-10 10:36:50 +0000140CPURegister CPURegisterFrom(Location location, Primitive::Type type) {
141 return IsFPType(type) ? CPURegister(FPRegisterFrom(location, type))
142 : CPURegister(RegisterFrom(location, type));
143}
144
Alexandre Rames67555f72014-11-18 10:55:16 +0000145CPURegister OutputCPURegister(HInstruction* instr) {
146 return IsFPType(instr->GetType()) ? static_cast<CPURegister>(OutputFPRegister(instr))
147 : static_cast<CPURegister>(OutputRegister(instr));
148}
149
150CPURegister InputCPURegisterAt(HInstruction* instr, int index) {
151 return IsFPType(instr->InputAt(index)->GetType())
152 ? static_cast<CPURegister>(InputFPRegisterAt(instr, index))
153 : static_cast<CPURegister>(InputRegisterAt(instr, index));
154}
155
Alexandre Rames5319def2014-10-23 10:03:10 +0100156int64_t Int64ConstantFrom(Location location) {
157 HConstant* instr = location.GetConstant();
158 return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue()
159 : instr->AsLongConstant()->GetValue();
160}
161
162Operand OperandFrom(Location location, Primitive::Type type) {
163 if (location.IsRegister()) {
164 return Operand(RegisterFrom(location, type));
165 } else {
166 return Operand(Int64ConstantFrom(location));
167 }
168}
169
170Operand InputOperandAt(HInstruction* instr, int input_index) {
171 return OperandFrom(instr->GetLocations()->InAt(input_index),
172 instr->InputAt(input_index)->GetType());
173}
174
175MemOperand StackOperandFrom(Location location) {
176 return MemOperand(sp, location.GetStackIndex());
177}
178
Serban Constantinescu02164b32014-11-13 14:05:07 +0000179MemOperand HeapOperand(const Register& base, size_t offset = 0) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100180 // A heap reference must be 32bit, so fit in a W register.
181 DCHECK(base.IsW());
Alexandre Rames67555f72014-11-18 10:55:16 +0000182 return MemOperand(base.X(), offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100183}
184
Alexandre Rames67555f72014-11-18 10:55:16 +0000185MemOperand HeapOperand(const Register& base, Offset offset) {
186 return HeapOperand(base, offset.SizeValue());
187}
188
189MemOperand HeapOperandFrom(Location location, Offset offset) {
190 return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100191}
192
193Location LocationFrom(const Register& reg) {
194 return Location::RegisterLocation(ARTRegCodeFromVIXL(reg.code()));
195}
196
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000197Location LocationFrom(const FPRegister& fpreg) {
198 return Location::FpuRegisterLocation(fpreg.code());
199}
200
Alexandre Rames5319def2014-10-23 10:03:10 +0100201} // namespace
202
203inline Condition ARM64Condition(IfCondition cond) {
204 switch (cond) {
205 case kCondEQ: return eq;
206 case kCondNE: return ne;
207 case kCondLT: return lt;
208 case kCondLE: return le;
209 case kCondGT: return gt;
210 case kCondGE: return ge;
211 default:
212 LOG(FATAL) << "Unknown if condition";
213 }
214 return nv; // Unreachable.
215}
216
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000217Location ARM64ReturnLocation(Primitive::Type return_type) {
218 DCHECK_NE(return_type, Primitive::kPrimVoid);
219 // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the
220 // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`,
221 // but we use the exact registers for clarity.
222 if (return_type == Primitive::kPrimFloat) {
223 return LocationFrom(s0);
224 } else if (return_type == Primitive::kPrimDouble) {
225 return LocationFrom(d0);
226 } else if (return_type == Primitive::kPrimLong) {
227 return LocationFrom(x0);
228 } else {
229 return LocationFrom(w0);
230 }
231}
232
Alexandre Rames5319def2014-10-23 10:03:10 +0100233static const Register kRuntimeParameterCoreRegisters[] = { x0, x1, x2, x3, x4, x5, x6, x7 };
234static constexpr size_t kRuntimeParameterCoreRegistersLength =
235 arraysize(kRuntimeParameterCoreRegisters);
236static const FPRegister kRuntimeParameterFpuRegisters[] = { };
237static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
238
239class InvokeRuntimeCallingConvention : public CallingConvention<Register, FPRegister> {
240 public:
241 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
242
243 InvokeRuntimeCallingConvention()
244 : CallingConvention(kRuntimeParameterCoreRegisters,
245 kRuntimeParameterCoreRegistersLength,
246 kRuntimeParameterFpuRegisters,
247 kRuntimeParameterFpuRegistersLength) {}
248
249 Location GetReturnLocation(Primitive::Type return_type);
250
251 private:
252 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
253};
254
255Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type return_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000256 return ARM64ReturnLocation(return_type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100257}
258
Alexandre Rames67555f72014-11-18 10:55:16 +0000259#define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
260#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
Alexandre Rames5319def2014-10-23 10:03:10 +0100261
262class SlowPathCodeARM64 : public SlowPathCode {
263 public:
264 SlowPathCodeARM64() : entry_label_(), exit_label_() {}
265
266 vixl::Label* GetEntryLabel() { return &entry_label_; }
267 vixl::Label* GetExitLabel() { return &exit_label_; }
268
269 private:
270 vixl::Label entry_label_;
271 vixl::Label exit_label_;
272
273 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM64);
274};
275
276class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
277 public:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000278 BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
279 Location index_location,
280 Location length_location)
281 : instruction_(instruction),
282 index_location_(index_location),
283 length_location_(length_location) {}
284
Alexandre Rames5319def2014-10-23 10:03:10 +0100285
Alexandre Rames67555f72014-11-18 10:55:16 +0000286 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000287 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100288 __ Bind(GetEntryLabel());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000289 // We're moving two locations to locations that could overlap, so we need a parallel
290 // move resolver.
291 InvokeRuntimeCallingConvention calling_convention;
292 codegen->EmitParallelMoves(
293 index_location_, LocationFrom(calling_convention.GetRegisterAt(0)),
294 length_location_, LocationFrom(calling_convention.GetRegisterAt(1)));
295 arm64_codegen->InvokeRuntime(
296 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc());
Alexandre Rames5319def2014-10-23 10:03:10 +0100297 }
298
299 private:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000300 HBoundsCheck* const instruction_;
301 const Location index_location_;
302 const Location length_location_;
303
Alexandre Rames5319def2014-10-23 10:03:10 +0100304 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
305};
306
Alexandre Rames67555f72014-11-18 10:55:16 +0000307class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 {
308 public:
309 explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : instruction_(instruction) {}
310
311 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
312 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
313 __ Bind(GetEntryLabel());
314 arm64_codegen->InvokeRuntime(
315 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
316 }
317
318 private:
319 HDivZeroCheck* const instruction_;
320 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64);
321};
322
323class LoadClassSlowPathARM64 : public SlowPathCodeARM64 {
324 public:
325 LoadClassSlowPathARM64(HLoadClass* cls,
326 HInstruction* at,
327 uint32_t dex_pc,
328 bool do_clinit)
329 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
330 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
331 }
332
333 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
334 LocationSummary* locations = at_->GetLocations();
335 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
336
337 __ Bind(GetEntryLabel());
338 codegen->SaveLiveRegisters(locations);
339
340 InvokeRuntimeCallingConvention calling_convention;
341 __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
342 arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W());
343 int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
344 : QUICK_ENTRY_POINT(pInitializeType);
345 arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
346
347 // Move the class to the desired location.
348 Location out = locations->Out();
349 if (out.IsValid()) {
350 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
351 Primitive::Type type = at_->GetType();
Alexandre Rames3e69f162014-12-10 10:36:50 +0000352 arm64_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
Alexandre Rames67555f72014-11-18 10:55:16 +0000353 }
354
355 codegen->RestoreLiveRegisters(locations);
356 __ B(GetExitLabel());
357 }
358
359 private:
360 // The class this slow path will load.
361 HLoadClass* const cls_;
362
363 // The instruction where this slow path is happening.
364 // (Might be the load class or an initialization check).
365 HInstruction* const at_;
366
367 // The dex PC of `at_`.
368 const uint32_t dex_pc_;
369
370 // Whether to initialize the class.
371 const bool do_clinit_;
372
373 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
374};
375
376class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
377 public:
378 explicit LoadStringSlowPathARM64(HLoadString* instruction) : instruction_(instruction) {}
379
380 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
381 LocationSummary* locations = instruction_->GetLocations();
382 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
383 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
384
385 __ Bind(GetEntryLabel());
386 codegen->SaveLiveRegisters(locations);
387
388 InvokeRuntimeCallingConvention calling_convention;
389 arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0).W());
390 __ Mov(calling_convention.GetRegisterAt(1).W(), instruction_->GetStringIndex());
391 arm64_codegen->InvokeRuntime(
392 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
393 Primitive::Type type = instruction_->GetType();
Alexandre Rames3e69f162014-12-10 10:36:50 +0000394 arm64_codegen->MoveLocation(locations->Out(), calling_convention.GetReturnLocation(type), type);
Alexandre Rames67555f72014-11-18 10:55:16 +0000395
396 codegen->RestoreLiveRegisters(locations);
397 __ B(GetExitLabel());
398 }
399
400 private:
401 HLoadString* const instruction_;
402
403 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
404};
405
Alexandre Rames5319def2014-10-23 10:03:10 +0100406class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
407 public:
408 explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {}
409
Alexandre Rames67555f72014-11-18 10:55:16 +0000410 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
411 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100412 __ Bind(GetEntryLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000413 arm64_codegen->InvokeRuntime(
414 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
Alexandre Rames5319def2014-10-23 10:03:10 +0100415 }
416
417 private:
418 HNullCheck* const instruction_;
419
420 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM64);
421};
422
Serban Constantinescu02164b32014-11-13 14:05:07 +0000423class StackOverflowCheckSlowPathARM64 : public SlowPathCodeARM64 {
424 public:
425 StackOverflowCheckSlowPathARM64() {}
426
427 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
428 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
429 __ Bind(GetEntryLabel());
430 arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowStackOverflow), nullptr, 0);
431 }
432
433 private:
434 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM64);
435};
436
Alexandre Rames5319def2014-10-23 10:03:10 +0100437class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 {
438 public:
439 explicit SuspendCheckSlowPathARM64(HSuspendCheck* instruction,
440 HBasicBlock* successor)
441 : instruction_(instruction), successor_(successor) {}
442
Alexandre Rames67555f72014-11-18 10:55:16 +0000443 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
444 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100445 __ Bind(GetEntryLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000446 codegen->SaveLiveRegisters(instruction_->GetLocations());
447 arm64_codegen->InvokeRuntime(
448 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
449 codegen->RestoreLiveRegisters(instruction_->GetLocations());
450 if (successor_ == nullptr) {
451 __ B(GetReturnLabel());
452 } else {
453 __ B(arm64_codegen->GetLabelOf(successor_));
454 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100455 }
456
457 vixl::Label* GetReturnLabel() {
458 DCHECK(successor_ == nullptr);
459 return &return_label_;
460 }
461
Alexandre Rames5319def2014-10-23 10:03:10 +0100462 private:
463 HSuspendCheck* const instruction_;
464 // If not null, the block to branch to after the suspend check.
465 HBasicBlock* const successor_;
466
467 // If `successor_` is null, the label to branch to after the suspend check.
468 vixl::Label return_label_;
469
470 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
471};
472
Alexandre Rames67555f72014-11-18 10:55:16 +0000473class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
474 public:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000475 TypeCheckSlowPathARM64(HInstruction* instruction,
476 Location class_to_check,
477 Location object_class,
478 uint32_t dex_pc)
479 : instruction_(instruction),
480 class_to_check_(class_to_check),
481 object_class_(object_class),
482 dex_pc_(dex_pc) {}
Alexandre Rames67555f72014-11-18 10:55:16 +0000483
484 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000485 LocationSummary* locations = instruction_->GetLocations();
486 DCHECK(instruction_->IsCheckCast()
487 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
488 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
489
Alexandre Rames67555f72014-11-18 10:55:16 +0000490 __ Bind(GetEntryLabel());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000491 codegen->SaveLiveRegisters(locations);
492
493 // We're moving two locations to locations that could overlap, so we need a parallel
494 // move resolver.
495 InvokeRuntimeCallingConvention calling_convention;
496 codegen->EmitParallelMoves(
497 class_to_check_, LocationFrom(calling_convention.GetRegisterAt(0)),
498 object_class_, LocationFrom(calling_convention.GetRegisterAt(1)));
499
500 if (instruction_->IsInstanceOf()) {
501 arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_);
502 Primitive::Type ret_type = instruction_->GetType();
503 Location ret_loc = calling_convention.GetReturnLocation(ret_type);
504 arm64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
505 } else {
506 DCHECK(instruction_->IsCheckCast());
507 arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_);
508 }
509
510 codegen->RestoreLiveRegisters(locations);
Serban Constantinescu02164b32014-11-13 14:05:07 +0000511 __ B(GetExitLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000512 }
513
514 private:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000515 HInstruction* const instruction_;
516 const Location class_to_check_;
517 const Location object_class_;
518 uint32_t dex_pc_;
519
Alexandre Rames67555f72014-11-18 10:55:16 +0000520 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64);
521};
522
Alexandre Rames5319def2014-10-23 10:03:10 +0100523#undef __
524
525Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
526 Location next_location;
527 if (type == Primitive::kPrimVoid) {
528 LOG(FATAL) << "Unreachable type " << type;
529 }
530
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000531 if (IsFPType(type) && (fp_index_ < calling_convention.GetNumberOfFpuRegisters())) {
532 next_location = LocationFrom(calling_convention.GetFpuRegisterAt(fp_index_++));
533 } else if (!IsFPType(type) && (gp_index_ < calling_convention.GetNumberOfRegisters())) {
534 next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++));
535 } else {
536 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
537 next_location = Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
538 : Location::StackSlot(stack_offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100539 }
540
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000541 // Space on the stack is reserved for all arguments.
542 stack_index_ += Is64BitType(type) ? 2 : 1;
Alexandre Rames5319def2014-10-23 10:03:10 +0100543 return next_location;
544}
545
546CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph)
547 : CodeGenerator(graph,
548 kNumberOfAllocatableRegisters,
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000549 kNumberOfAllocatableFPRegisters,
Alexandre Rames5319def2014-10-23 10:03:10 +0100550 kNumberOfAllocatableRegisterPairs),
551 block_labels_(nullptr),
552 location_builder_(graph, this),
Alexandre Rames3e69f162014-12-10 10:36:50 +0000553 instruction_visitor_(graph, this),
554 move_resolver_(graph->GetArena(), this) {}
Alexandre Rames5319def2014-10-23 10:03:10 +0100555
Alexandre Rames67555f72014-11-18 10:55:16 +0000556#undef __
557#define __ GetVIXLAssembler()->
Alexandre Rames5319def2014-10-23 10:03:10 +0100558
Serban Constantinescu32f5b4d2014-11-25 20:05:46 +0000559void CodeGeneratorARM64::Finalize(CodeAllocator* allocator) {
560 // Ensure we emit the literal pool.
561 __ FinalizeCode();
562 CodeGenerator::Finalize(allocator);
563}
564
Alexandre Rames3e69f162014-12-10 10:36:50 +0000565void ParallelMoveResolverARM64::EmitMove(size_t index) {
566 MoveOperands* move = moves_.Get(index);
567 codegen_->MoveLocation(move->GetDestination(), move->GetSource());
568}
569
570void ParallelMoveResolverARM64::EmitSwap(size_t index) {
571 MoveOperands* move = moves_.Get(index);
572 codegen_->SwapLocations(move->GetDestination(), move->GetSource());
573}
574
575void ParallelMoveResolverARM64::RestoreScratch(int reg) {
576 __ Pop(Register(VIXLRegCodeFromART(reg), kXRegSize));
577}
578
579void ParallelMoveResolverARM64::SpillScratch(int reg) {
580 __ Push(Register(VIXLRegCodeFromART(reg), kXRegSize));
581}
582
Alexandre Rames5319def2014-10-23 10:03:10 +0100583void CodeGeneratorARM64::GenerateFrameEntry() {
Serban Constantinescu02164b32014-11-13 14:05:07 +0000584 bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kArm64) || !IsLeafMethod();
585 if (do_overflow_check) {
586 UseScratchRegisterScope temps(GetVIXLAssembler());
587 Register temp = temps.AcquireX();
588 if (kExplicitStackOverflowCheck) {
589 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM64();
590 AddSlowPath(slow_path);
591
592 __ Ldr(temp, MemOperand(tr, Thread::StackEndOffset<kArm64WordSize>().Int32Value()));
593 __ Cmp(sp, temp);
594 __ B(lo, slow_path->GetEntryLabel());
595 } else {
596 __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
597 __ Ldr(wzr, MemOperand(temp, 0));
598 RecordPcInfo(nullptr, 0);
599 }
600 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100601
602 CPURegList preserved_regs = GetFramePreservedRegisters();
603 int frame_size = GetFrameSize();
604 core_spill_mask_ |= preserved_regs.list();
605
606 __ Str(w0, MemOperand(sp, -frame_size, PreIndex));
607 __ PokeCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
608
609 // Stack layout:
610 // sp[frame_size - 8] : lr.
611 // ... : other preserved registers.
612 // sp[frame_size - regs_size]: first preserved register.
613 // ... : reserved frame space.
Alexandre Rames67555f72014-11-18 10:55:16 +0000614 // sp[0] : current method.
Alexandre Rames5319def2014-10-23 10:03:10 +0100615}
616
617void CodeGeneratorARM64::GenerateFrameExit() {
618 int frame_size = GetFrameSize();
619 CPURegList preserved_regs = GetFramePreservedRegisters();
620 __ PeekCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
621 __ Drop(frame_size);
622}
623
624void CodeGeneratorARM64::Bind(HBasicBlock* block) {
625 __ Bind(GetLabelOf(block));
626}
627
Alexandre Rames5319def2014-10-23 10:03:10 +0100628void CodeGeneratorARM64::Move(HInstruction* instruction,
629 Location location,
630 HInstruction* move_for) {
631 LocationSummary* locations = instruction->GetLocations();
632 if (locations != nullptr && locations->Out().Equals(location)) {
633 return;
634 }
635
636 Primitive::Type type = instruction->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000637 DCHECK_NE(type, Primitive::kPrimVoid);
Alexandre Rames5319def2014-10-23 10:03:10 +0100638
639 if (instruction->IsIntConstant() || instruction->IsLongConstant()) {
640 int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue()
641 : instruction->AsLongConstant()->GetValue();
642 if (location.IsRegister()) {
643 Register dst = RegisterFrom(location, type);
644 DCHECK((instruction->IsIntConstant() && dst.Is32Bits()) ||
645 (instruction->IsLongConstant() && dst.Is64Bits()));
646 __ Mov(dst, value);
647 } else {
648 DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
Alexandre Rames67555f72014-11-18 10:55:16 +0000649 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100650 Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
651 __ Mov(temp, value);
652 __ Str(temp, StackOperandFrom(location));
653 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000654 } else if (instruction->IsTemporary()) {
655 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000656 MoveLocation(location, temp_location, type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100657 } else if (instruction->IsLoadLocal()) {
658 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000659 if (Is64BitType(type)) {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000660 MoveLocation(location, Location::DoubleStackSlot(stack_slot), type);
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000661 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000662 MoveLocation(location, Location::StackSlot(stack_slot), type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100663 }
664
665 } else {
666 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000667 MoveLocation(location, locations->Out(), type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100668 }
669}
670
671size_t CodeGeneratorARM64::FrameEntrySpillSize() const {
672 return GetFramePreservedRegistersSize();
673}
674
675Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const {
676 Primitive::Type type = load->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000677
Alexandre Rames5319def2014-10-23 10:03:10 +0100678 switch (type) {
679 case Primitive::kPrimNot:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000680 case Primitive::kPrimInt:
681 case Primitive::kPrimFloat:
682 return Location::StackSlot(GetStackSlot(load->GetLocal()));
683
684 case Primitive::kPrimLong:
685 case Primitive::kPrimDouble:
686 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
687
Alexandre Rames5319def2014-10-23 10:03:10 +0100688 case Primitive::kPrimBoolean:
689 case Primitive::kPrimByte:
690 case Primitive::kPrimChar:
691 case Primitive::kPrimShort:
Alexandre Rames5319def2014-10-23 10:03:10 +0100692 case Primitive::kPrimVoid:
Alexandre Rames5319def2014-10-23 10:03:10 +0100693 LOG(FATAL) << "Unexpected type " << type;
694 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000695
Alexandre Rames5319def2014-10-23 10:03:10 +0100696 LOG(FATAL) << "Unreachable";
697 return Location::NoLocation();
698}
699
700void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
Alexandre Rames67555f72014-11-18 10:55:16 +0000701 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100702 Register card = temps.AcquireX();
Serban Constantinescu02164b32014-11-13 14:05:07 +0000703 Register temp = temps.AcquireW(); // Index within the CardTable - 32bit.
Alexandre Rames5319def2014-10-23 10:03:10 +0100704 vixl::Label done;
705 __ Cbz(value, &done);
706 __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
707 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
Serban Constantinescu02164b32014-11-13 14:05:07 +0000708 __ Strb(card, MemOperand(card, temp.X()));
Alexandre Rames5319def2014-10-23 10:03:10 +0100709 __ Bind(&done);
710}
711
712void CodeGeneratorARM64::SetupBlockedRegisters() const {
713 // Block reserved registers:
714 // ip0 (VIXL temporary)
715 // ip1 (VIXL temporary)
Serban Constantinescu02164b32014-11-13 14:05:07 +0000716 // tr
Alexandre Rames5319def2014-10-23 10:03:10 +0100717 // lr
718 // sp is not part of the allocatable registers, so we don't need to block it.
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000719 // TODO: Avoid blocking callee-saved registers, and instead preserve them
720 // where necessary.
Alexandre Rames5319def2014-10-23 10:03:10 +0100721 CPURegList reserved_core_registers = vixl_reserved_core_registers;
722 reserved_core_registers.Combine(runtime_reserved_core_registers);
Alexandre Rames5319def2014-10-23 10:03:10 +0100723 reserved_core_registers.Combine(quick_callee_saved_registers);
724 while (!reserved_core_registers.IsEmpty()) {
725 blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true;
726 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000727 CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
728 reserved_fp_registers.Combine(CPURegList::GetCalleeSavedFP());
729 while (!reserved_core_registers.IsEmpty()) {
730 blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().code()] = true;
731 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100732}
733
734Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const {
735 if (type == Primitive::kPrimVoid) {
736 LOG(FATAL) << "Unreachable type " << type;
737 }
738
Alexandre Rames5319def2014-10-23 10:03:10 +0100739 if (IsFPType(type)) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000740 ssize_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfAllocatableFPRegisters);
741 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100742 return Location::FpuRegisterLocation(reg);
743 } else {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000744 ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfAllocatableRegisters);
745 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100746 return Location::RegisterLocation(reg);
747 }
748}
749
Alexandre Rames3e69f162014-12-10 10:36:50 +0000750size_t CodeGeneratorARM64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
751 Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
752 __ Str(reg, MemOperand(sp, stack_index));
753 return kArm64WordSize;
754}
755
756size_t CodeGeneratorARM64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
757 Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
758 __ Ldr(reg, MemOperand(sp, stack_index));
759 return kArm64WordSize;
760}
761
762size_t CodeGeneratorARM64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
763 FPRegister reg = FPRegister(reg_id, kDRegSize);
764 __ Str(reg, MemOperand(sp, stack_index));
765 return kArm64WordSize;
766}
767
768size_t CodeGeneratorARM64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
769 FPRegister reg = FPRegister(reg_id, kDRegSize);
770 __ Ldr(reg, MemOperand(sp, stack_index));
771 return kArm64WordSize;
772}
773
Alexandre Rames5319def2014-10-23 10:03:10 +0100774void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
775 stream << Arm64ManagedRegister::FromXRegister(XRegister(reg));
776}
777
778void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
779 stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
780}
781
Alexandre Rames67555f72014-11-18 10:55:16 +0000782void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
783 if (constant->IsIntConstant() || constant->IsLongConstant()) {
784 __ Mov(Register(destination),
785 constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
786 : constant->AsLongConstant()->GetValue());
787 } else if (constant->IsFloatConstant()) {
788 __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
789 } else {
790 DCHECK(constant->IsDoubleConstant());
791 __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue());
792 }
793}
794
Alexandre Rames3e69f162014-12-10 10:36:50 +0000795
796static bool CoherentConstantAndType(Location constant, Primitive::Type type) {
797 DCHECK(constant.IsConstant());
798 HConstant* cst = constant.GetConstant();
799 return (cst->IsIntConstant() && type == Primitive::kPrimInt) ||
800 (cst->IsLongConstant() && type == Primitive::kPrimLong) ||
801 (cst->IsFloatConstant() && type == Primitive::kPrimFloat) ||
802 (cst->IsDoubleConstant() && type == Primitive::kPrimDouble);
803}
804
805void CodeGeneratorARM64::MoveLocation(Location destination, Location source, Primitive::Type type) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000806 if (source.Equals(destination)) {
807 return;
808 }
Alexandre Rames3e69f162014-12-10 10:36:50 +0000809
810 // A valid move can always be inferred from the destination and source
811 // locations. When moving from and to a register, the argument type can be
812 // used to generate 32bit instead of 64bit moves. In debug mode we also
813 // checks the coherency of the locations and the type.
814 bool unspecified_type = (type == Primitive::kPrimVoid);
815
816 if (destination.IsRegister() || destination.IsFpuRegister()) {
817 if (unspecified_type) {
818 HConstant* src_cst = source.IsConstant() ? source.GetConstant() : nullptr;
819 if (source.IsStackSlot() ||
820 (src_cst != nullptr && (src_cst->IsIntConstant() || src_cst->IsFloatConstant()))) {
821 // For stack slots and 32bit constants, a 64bit type is appropriate.
822 type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
Alexandre Rames67555f72014-11-18 10:55:16 +0000823 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000824 // If the source is a double stack slot or a 64bit constant, a 64bit
825 // type is appropriate. Else the source is a register, and since the
826 // type has not been specified, we chose a 64bit type to force a 64bit
827 // move.
828 type = destination.IsRegister() ? Primitive::kPrimLong : Primitive::kPrimDouble;
Alexandre Rames67555f72014-11-18 10:55:16 +0000829 }
Alexandre Rames3e69f162014-12-10 10:36:50 +0000830 }
831 DCHECK((destination.IsFpuRegister() && IsFPType(type)) ||
832 (destination.IsRegister() && !IsFPType(type)));
833 CPURegister dst = CPURegisterFrom(destination, type);
834 if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
835 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
836 __ Ldr(dst, StackOperandFrom(source));
837 } else if (source.IsConstant()) {
838 DCHECK(CoherentConstantAndType(source, type));
839 MoveConstant(dst, source.GetConstant());
840 } else {
841 if (destination.IsRegister()) {
842 __ Mov(Register(dst), RegisterFrom(source, type));
843 } else {
844 __ Fmov(FPRegister(dst), FPRegisterFrom(source, type));
845 }
846 }
847
848 } else { // The destination is not a register. It must be a stack slot.
849 DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
850 if (source.IsRegister() || source.IsFpuRegister()) {
851 if (unspecified_type) {
852 if (source.IsRegister()) {
853 type = destination.IsStackSlot() ? Primitive::kPrimInt : Primitive::kPrimLong;
854 } else {
855 type = destination.IsStackSlot() ? Primitive::kPrimFloat : Primitive::kPrimDouble;
856 }
857 }
858 DCHECK((destination.IsDoubleStackSlot() == Is64BitType(type)) &&
859 (source.IsFpuRegister() == IsFPType(type)));
860 __ Str(CPURegisterFrom(source, type), StackOperandFrom(destination));
861 } else if (source.IsConstant()) {
862 DCHECK(unspecified_type || CoherentConstantAndType(source, type));
863 UseScratchRegisterScope temps(GetVIXLAssembler());
864 HConstant* src_cst = source.GetConstant();
865 CPURegister temp;
866 if (src_cst->IsIntConstant()) {
867 temp = temps.AcquireW();
868 } else if (src_cst->IsLongConstant()) {
869 temp = temps.AcquireX();
870 } else if (src_cst->IsFloatConstant()) {
871 temp = temps.AcquireS();
872 } else {
873 DCHECK(src_cst->IsDoubleConstant());
874 temp = temps.AcquireD();
875 }
876 MoveConstant(temp, src_cst);
Alexandre Rames67555f72014-11-18 10:55:16 +0000877 __ Str(temp, StackOperandFrom(destination));
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000878 } else {
Alexandre Rames67555f72014-11-18 10:55:16 +0000879 DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000880 DCHECK(source.IsDoubleStackSlot() == destination.IsDoubleStackSlot());
Alexandre Rames67555f72014-11-18 10:55:16 +0000881 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000882 // There is generally less pressure on FP registers.
883 FPRegister temp = destination.IsDoubleStackSlot() ? temps.AcquireD() : temps.AcquireS();
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000884 __ Ldr(temp, StackOperandFrom(source));
885 __ Str(temp, StackOperandFrom(destination));
886 }
887 }
888}
889
Alexandre Rames3e69f162014-12-10 10:36:50 +0000890void CodeGeneratorARM64::SwapLocations(Location loc1, Location loc2) {
891 DCHECK(!loc1.IsConstant());
892 DCHECK(!loc2.IsConstant());
893
894 if (loc1.Equals(loc2)) {
895 return;
896 }
897
898 UseScratchRegisterScope temps(GetAssembler()->vixl_masm_);
899
900 bool is_slot1 = loc1.IsStackSlot() || loc1.IsDoubleStackSlot();
901 bool is_slot2 = loc2.IsStackSlot() || loc2.IsDoubleStackSlot();
902 bool is_fp_reg1 = loc1.IsFpuRegister();
903 bool is_fp_reg2 = loc2.IsFpuRegister();
904
905 if (loc2.IsRegister() && loc1.IsRegister()) {
906 Register r1 = XRegisterFrom(loc1);
907 Register r2 = XRegisterFrom(loc2);
908 Register tmp = temps.AcquireSameSizeAs(r1);
909 __ Mov(tmp, r2);
910 __ Mov(r2, r1);
911 __ Mov(r1, tmp);
912 } else if (is_fp_reg2 && is_fp_reg1) {
913 FPRegister r1 = DRegisterFrom(loc1);
914 FPRegister r2 = DRegisterFrom(loc2);
915 FPRegister tmp = temps.AcquireSameSizeAs(r1);
916 __ Fmov(tmp, r2);
917 __ Fmov(r2, r1);
918 __ Fmov(r1, tmp);
919 } else if (is_slot1 != is_slot2) {
920 MemOperand mem = StackOperandFrom(is_slot1 ? loc1 : loc2);
921 Location reg_loc = is_slot1 ? loc2 : loc1;
922 CPURegister reg, tmp;
923 if (reg_loc.IsFpuRegister()) {
924 reg = DRegisterFrom(reg_loc);
925 tmp = temps.AcquireD();
926 } else {
927 reg = XRegisterFrom(reg_loc);
928 tmp = temps.AcquireX();
929 }
930 __ Ldr(tmp, mem);
931 __ Str(reg, mem);
932 if (reg_loc.IsFpuRegister()) {
933 __ Fmov(FPRegister(reg), FPRegister(tmp));
934 } else {
935 __ Mov(Register(reg), Register(tmp));
936 }
937 } else if (is_slot1 && is_slot2) {
938 MemOperand mem1 = StackOperandFrom(loc1);
939 MemOperand mem2 = StackOperandFrom(loc2);
940 Register tmp1 = loc1.IsStackSlot() ? temps.AcquireW() : temps.AcquireX();
941 Register tmp2 = temps.AcquireSameSizeAs(tmp1);
942 __ Ldr(tmp1, mem1);
943 __ Ldr(tmp2, mem2);
944 __ Str(tmp1, mem2);
945 __ Str(tmp2, mem1);
946 } else {
947 LOG(FATAL) << "Unimplemented";
948 }
949}
950
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000951void CodeGeneratorARM64::Load(Primitive::Type type,
Alexandre Rames67555f72014-11-18 10:55:16 +0000952 vixl::CPURegister dst,
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000953 const vixl::MemOperand& src) {
954 switch (type) {
955 case Primitive::kPrimBoolean:
Alexandre Rames67555f72014-11-18 10:55:16 +0000956 __ Ldrb(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000957 break;
958 case Primitive::kPrimByte:
Alexandre Rames67555f72014-11-18 10:55:16 +0000959 __ Ldrsb(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000960 break;
961 case Primitive::kPrimShort:
Alexandre Rames67555f72014-11-18 10:55:16 +0000962 __ Ldrsh(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000963 break;
964 case Primitive::kPrimChar:
Alexandre Rames67555f72014-11-18 10:55:16 +0000965 __ Ldrh(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000966 break;
967 case Primitive::kPrimInt:
968 case Primitive::kPrimNot:
969 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000970 case Primitive::kPrimFloat:
971 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +0000972 DCHECK(dst.Is64Bits() == Is64BitType(type));
973 __ Ldr(dst, src);
974 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000975 case Primitive::kPrimVoid:
976 LOG(FATAL) << "Unreachable type " << type;
977 }
978}
979
980void CodeGeneratorARM64::Store(Primitive::Type type,
Alexandre Rames67555f72014-11-18 10:55:16 +0000981 vixl::CPURegister rt,
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000982 const vixl::MemOperand& dst) {
983 switch (type) {
984 case Primitive::kPrimBoolean:
985 case Primitive::kPrimByte:
Alexandre Rames67555f72014-11-18 10:55:16 +0000986 __ Strb(Register(rt), dst);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000987 break;
988 case Primitive::kPrimChar:
989 case Primitive::kPrimShort:
Alexandre Rames67555f72014-11-18 10:55:16 +0000990 __ Strh(Register(rt), dst);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000991 break;
992 case Primitive::kPrimInt:
993 case Primitive::kPrimNot:
994 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000995 case Primitive::kPrimFloat:
996 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +0000997 DCHECK(rt.Is64Bits() == Is64BitType(type));
998 __ Str(rt, dst);
999 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001000 case Primitive::kPrimVoid:
1001 LOG(FATAL) << "Unreachable type " << type;
1002 }
1003}
1004
Alexandre Rames67555f72014-11-18 10:55:16 +00001005void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) {
1006 DCHECK(current_method.IsW());
1007 __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
1008}
1009
1010void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
1011 HInstruction* instruction,
1012 uint32_t dex_pc) {
1013 __ Ldr(lr, MemOperand(tr, entry_point_offset));
1014 __ Blr(lr);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001015 if (instruction != nullptr) {
1016 RecordPcInfo(instruction, dex_pc);
1017 DCHECK(instruction->IsSuspendCheck()
1018 || instruction->IsBoundsCheck()
1019 || instruction->IsNullCheck()
1020 || instruction->IsDivZeroCheck()
1021 || !IsLeafMethod());
1022 }
Alexandre Rames67555f72014-11-18 10:55:16 +00001023}
1024
1025void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
1026 vixl::Register class_reg) {
1027 UseScratchRegisterScope temps(GetVIXLAssembler());
1028 Register temp = temps.AcquireW();
1029 __ Ldr(temp, HeapOperand(class_reg, mirror::Class::StatusOffset()));
1030 __ Cmp(temp, mirror::Class::kStatusInitialized);
1031 __ B(lt, slow_path->GetEntryLabel());
Serban Constantinescu02164b32014-11-13 14:05:07 +00001032 // Even if the initialized flag is set, we need to ensure consistent memory ordering.
1033 __ Dmb(InnerShareable, BarrierReads);
Alexandre Rames67555f72014-11-18 10:55:16 +00001034 __ Bind(slow_path->GetExitLabel());
1035}
Alexandre Rames5319def2014-10-23 10:03:10 +01001036
Serban Constantinescu02164b32014-11-13 14:05:07 +00001037void InstructionCodeGeneratorARM64::GenerateSuspendCheck(HSuspendCheck* instruction,
1038 HBasicBlock* successor) {
1039 SuspendCheckSlowPathARM64* slow_path =
1040 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM64(instruction, successor);
1041 codegen_->AddSlowPath(slow_path);
1042 UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
1043 Register temp = temps.AcquireW();
1044
1045 __ Ldrh(temp, MemOperand(tr, Thread::ThreadFlagsOffset<kArm64WordSize>().SizeValue()));
1046 if (successor == nullptr) {
1047 __ Cbnz(temp, slow_path->GetEntryLabel());
1048 __ Bind(slow_path->GetReturnLabel());
1049 } else {
1050 __ Cbz(temp, codegen_->GetLabelOf(successor));
1051 __ B(slow_path->GetEntryLabel());
1052 // slow_path will return to GetLabelOf(successor).
1053 }
1054}
1055
Alexandre Rames5319def2014-10-23 10:03:10 +01001056InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
1057 CodeGeneratorARM64* codegen)
1058 : HGraphVisitor(graph),
1059 assembler_(codegen->GetAssembler()),
1060 codegen_(codegen) {}
1061
1062#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
Alexandre Rames3e69f162014-12-10 10:36:50 +00001063 /* No unimplemented IR. */
Alexandre Rames5319def2014-10-23 10:03:10 +01001064
1065#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
1066
1067enum UnimplementedInstructionBreakCode {
Alexandre Rames67555f72014-11-18 10:55:16 +00001068 // Using a base helps identify when we hit such breakpoints.
1069 UnimplementedInstructionBreakCodeBaseCode = 0x900,
Alexandre Rames5319def2014-10-23 10:03:10 +01001070#define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name),
1071 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION)
1072#undef ENUM_UNIMPLEMENTED_INSTRUCTION
1073};
1074
1075#define DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS(name) \
1076 void InstructionCodeGeneratorARM64::Visit##name(H##name* instr) { \
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001077 UNUSED(instr); \
Alexandre Rames5319def2014-10-23 10:03:10 +01001078 __ Brk(UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name)); \
1079 } \
1080 void LocationsBuilderARM64::Visit##name(H##name* instr) { \
1081 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); \
1082 locations->SetOut(Location::Any()); \
1083 }
1084 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS)
1085#undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS
1086
1087#undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE
Alexandre Rames67555f72014-11-18 10:55:16 +00001088#undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION
Alexandre Rames5319def2014-10-23 10:03:10 +01001089
Alexandre Rames67555f72014-11-18 10:55:16 +00001090void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001091 DCHECK_EQ(instr->InputCount(), 2U);
1092 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1093 Primitive::Type type = instr->GetResultType();
1094 switch (type) {
1095 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001096 case Primitive::kPrimLong:
Alexandre Rames5319def2014-10-23 10:03:10 +01001097 locations->SetInAt(0, Location::RequiresRegister());
1098 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001099 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001100 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001101
1102 case Primitive::kPrimFloat:
1103 case Primitive::kPrimDouble:
1104 locations->SetInAt(0, Location::RequiresFpuRegister());
1105 locations->SetInAt(1, Location::RequiresFpuRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00001106 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001107 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001108
Alexandre Rames5319def2014-10-23 10:03:10 +01001109 default:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001110 LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +01001111 }
1112}
1113
Alexandre Rames67555f72014-11-18 10:55:16 +00001114void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001115 Primitive::Type type = instr->GetType();
Alexandre Rames5319def2014-10-23 10:03:10 +01001116
1117 switch (type) {
1118 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001119 case Primitive::kPrimLong: {
1120 Register dst = OutputRegister(instr);
1121 Register lhs = InputRegisterAt(instr, 0);
1122 Operand rhs = InputOperandAt(instr, 1);
Alexandre Rames5319def2014-10-23 10:03:10 +01001123 if (instr->IsAdd()) {
1124 __ Add(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001125 } else if (instr->IsAnd()) {
1126 __ And(dst, lhs, rhs);
1127 } else if (instr->IsOr()) {
1128 __ Orr(dst, lhs, rhs);
1129 } else if (instr->IsSub()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001130 __ Sub(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001131 } else {
1132 DCHECK(instr->IsXor());
1133 __ Eor(dst, lhs, rhs);
Alexandre Rames5319def2014-10-23 10:03:10 +01001134 }
1135 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001136 }
1137 case Primitive::kPrimFloat:
1138 case Primitive::kPrimDouble: {
1139 FPRegister dst = OutputFPRegister(instr);
1140 FPRegister lhs = InputFPRegisterAt(instr, 0);
1141 FPRegister rhs = InputFPRegisterAt(instr, 1);
1142 if (instr->IsAdd()) {
1143 __ Fadd(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001144 } else if (instr->IsSub()) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001145 __ Fsub(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001146 } else {
1147 LOG(FATAL) << "Unexpected floating-point binary operation";
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001148 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001149 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001150 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001151 default:
Alexandre Rames67555f72014-11-18 10:55:16 +00001152 LOG(FATAL) << "Unexpected binary operation type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +01001153 }
1154}
1155
Serban Constantinescu02164b32014-11-13 14:05:07 +00001156void LocationsBuilderARM64::HandleShift(HBinaryOperation* instr) {
1157 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
1158
1159 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1160 Primitive::Type type = instr->GetResultType();
1161 switch (type) {
1162 case Primitive::kPrimInt:
1163 case Primitive::kPrimLong: {
1164 locations->SetInAt(0, Location::RequiresRegister());
1165 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1166 locations->SetOut(Location::RequiresRegister());
1167 break;
1168 }
1169 default:
1170 LOG(FATAL) << "Unexpected shift type " << type;
1171 }
1172}
1173
1174void InstructionCodeGeneratorARM64::HandleShift(HBinaryOperation* instr) {
1175 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
1176
1177 Primitive::Type type = instr->GetType();
1178 switch (type) {
1179 case Primitive::kPrimInt:
1180 case Primitive::kPrimLong: {
1181 Register dst = OutputRegister(instr);
1182 Register lhs = InputRegisterAt(instr, 0);
1183 Operand rhs = InputOperandAt(instr, 1);
1184 if (rhs.IsImmediate()) {
1185 uint32_t shift_value = (type == Primitive::kPrimInt)
1186 ? static_cast<uint32_t>(rhs.immediate() & kMaxIntShiftValue)
1187 : static_cast<uint32_t>(rhs.immediate() & kMaxLongShiftValue);
1188 if (instr->IsShl()) {
1189 __ Lsl(dst, lhs, shift_value);
1190 } else if (instr->IsShr()) {
1191 __ Asr(dst, lhs, shift_value);
1192 } else {
1193 __ Lsr(dst, lhs, shift_value);
1194 }
1195 } else {
1196 Register rhs_reg = dst.IsX() ? rhs.reg().X() : rhs.reg().W();
1197
1198 if (instr->IsShl()) {
1199 __ Lsl(dst, lhs, rhs_reg);
1200 } else if (instr->IsShr()) {
1201 __ Asr(dst, lhs, rhs_reg);
1202 } else {
1203 __ Lsr(dst, lhs, rhs_reg);
1204 }
1205 }
1206 break;
1207 }
1208 default:
1209 LOG(FATAL) << "Unexpected shift operation type " << type;
1210 }
1211}
1212
Alexandre Rames5319def2014-10-23 10:03:10 +01001213void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001214 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001215}
1216
1217void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001218 HandleBinaryOp(instruction);
1219}
1220
1221void LocationsBuilderARM64::VisitAnd(HAnd* instruction) {
1222 HandleBinaryOp(instruction);
1223}
1224
1225void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) {
1226 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001227}
1228
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001229void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
1230 LocationSummary* locations =
1231 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1232 locations->SetInAt(0, Location::RequiresRegister());
1233 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1234 locations->SetOut(Location::RequiresRegister());
1235}
1236
1237void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
1238 LocationSummary* locations = instruction->GetLocations();
1239 Primitive::Type type = instruction->GetType();
1240 Register obj = InputRegisterAt(instruction, 0);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001241 Location index = locations->InAt(1);
1242 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001243 MemOperand source = HeapOperand(obj);
Alexandre Rames67555f72014-11-18 10:55:16 +00001244 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001245
1246 if (index.IsConstant()) {
1247 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001248 source = HeapOperand(obj, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001249 } else {
1250 Register temp = temps.AcquireSameSizeAs(obj);
1251 Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
1252 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type)));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001253 source = HeapOperand(temp, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001254 }
1255
Alexandre Rames67555f72014-11-18 10:55:16 +00001256 codegen_->Load(type, OutputCPURegister(instruction), source);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001257}
1258
Alexandre Rames5319def2014-10-23 10:03:10 +01001259void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
1260 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1261 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001262 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001263}
1264
1265void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
1266 __ Ldr(OutputRegister(instruction),
1267 HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset()));
1268}
1269
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001270void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
1271 Primitive::Type value_type = instruction->GetComponentType();
1272 bool is_object = value_type == Primitive::kPrimNot;
1273 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1274 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1275 if (is_object) {
1276 InvokeRuntimeCallingConvention calling_convention;
1277 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
1278 locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
1279 locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
1280 } else {
1281 locations->SetInAt(0, Location::RequiresRegister());
1282 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1283 locations->SetInAt(2, Location::RequiresRegister());
1284 }
1285}
1286
1287void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
1288 Primitive::Type value_type = instruction->GetComponentType();
1289 if (value_type == Primitive::kPrimNot) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001290 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
1291
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001292 } else {
1293 LocationSummary* locations = instruction->GetLocations();
1294 Register obj = InputRegisterAt(instruction, 0);
Alexandre Rames67555f72014-11-18 10:55:16 +00001295 CPURegister value = InputCPURegisterAt(instruction, 2);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001296 Location index = locations->InAt(1);
1297 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001298 MemOperand destination = HeapOperand(obj);
Alexandre Rames67555f72014-11-18 10:55:16 +00001299 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001300
1301 if (index.IsConstant()) {
1302 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001303 destination = HeapOperand(obj, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001304 } else {
1305 Register temp = temps.AcquireSameSizeAs(obj);
1306 Register index_reg = InputRegisterAt(instruction, 1);
1307 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type)));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001308 destination = HeapOperand(temp, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001309 }
1310
1311 codegen_->Store(value_type, value, destination);
1312 }
1313}
1314
Alexandre Rames67555f72014-11-18 10:55:16 +00001315void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1316 LocationSummary* locations =
1317 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1318 locations->SetInAt(0, Location::RequiresRegister());
1319 locations->SetInAt(1, Location::RequiresRegister());
1320 if (instruction->HasUses()) {
1321 locations->SetOut(Location::SameAsFirstInput());
1322 }
1323}
1324
1325void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
Alexandre Rames3e69f162014-12-10 10:36:50 +00001326 LocationSummary* locations = instruction->GetLocations();
1327 BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(
1328 instruction, locations->InAt(0), locations->InAt(1));
Alexandre Rames67555f72014-11-18 10:55:16 +00001329 codegen_->AddSlowPath(slow_path);
1330
1331 __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
1332 __ B(slow_path->GetEntryLabel(), hs);
1333}
1334
1335void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
1336 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1337 instruction, LocationSummary::kCallOnSlowPath);
1338 locations->SetInAt(0, Location::RequiresRegister());
1339 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Rames3e69f162014-12-10 10:36:50 +00001340 locations->AddTemp(Location::RequiresRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00001341}
1342
1343void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
Alexandre Rames3e69f162014-12-10 10:36:50 +00001344 LocationSummary* locations = instruction->GetLocations();
Alexandre Rames67555f72014-11-18 10:55:16 +00001345 Register obj = InputRegisterAt(instruction, 0);;
1346 Register cls = InputRegisterAt(instruction, 1);;
Alexandre Rames3e69f162014-12-10 10:36:50 +00001347 Register obj_cls = WRegisterFrom(instruction->GetLocations()->GetTemp(0));
Alexandre Rames67555f72014-11-18 10:55:16 +00001348
Alexandre Rames3e69f162014-12-10 10:36:50 +00001349 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(
1350 instruction, locations->InAt(1), LocationFrom(obj_cls), instruction->GetDexPc());
Alexandre Rames67555f72014-11-18 10:55:16 +00001351 codegen_->AddSlowPath(slow_path);
1352
1353 // TODO: avoid this check if we know obj is not null.
1354 __ Cbz(obj, slow_path->GetExitLabel());
1355 // Compare the class of `obj` with `cls`.
Alexandre Rames3e69f162014-12-10 10:36:50 +00001356 __ Ldr(obj_cls, HeapOperand(obj, mirror::Object::ClassOffset()));
1357 __ Cmp(obj_cls, cls);
Alexandre Rames67555f72014-11-18 10:55:16 +00001358 __ B(ne, slow_path->GetEntryLabel());
1359 __ Bind(slow_path->GetExitLabel());
1360}
1361
1362void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) {
1363 LocationSummary* locations =
1364 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
1365 locations->SetInAt(0, Location::RequiresRegister());
1366 if (check->HasUses()) {
1367 locations->SetOut(Location::SameAsFirstInput());
1368 }
1369}
1370
1371void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) {
1372 // We assume the class is not null.
1373 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
1374 check->GetLoadClass(), check, check->GetDexPc(), true);
1375 codegen_->AddSlowPath(slow_path);
1376 GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
1377}
1378
Serban Constantinescu02164b32014-11-13 14:05:07 +00001379void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001380 LocationSummary* locations =
Serban Constantinescu02164b32014-11-13 14:05:07 +00001381 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
1382 Primitive::Type in_type = compare->InputAt(0)->GetType();
Alexandre Rames5319def2014-10-23 10:03:10 +01001383 switch (in_type) {
1384 case Primitive::kPrimLong: {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001385 locations->SetInAt(0, Location::RequiresRegister());
1386 locations->SetInAt(1, Location::RegisterOrConstant(compare->InputAt(1)));
1387 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1388 break;
1389 }
1390 case Primitive::kPrimFloat:
1391 case Primitive::kPrimDouble: {
1392 locations->SetInAt(0, Location::RequiresFpuRegister());
1393 locations->SetInAt(1, Location::RequiresFpuRegister());
1394 locations->SetOut(Location::RequiresRegister());
1395 break;
1396 }
1397 default:
1398 LOG(FATAL) << "Unexpected type for compare operation " << in_type;
1399 }
1400}
1401
1402void InstructionCodeGeneratorARM64::VisitCompare(HCompare* compare) {
1403 Primitive::Type in_type = compare->InputAt(0)->GetType();
1404
1405 // 0 if: left == right
1406 // 1 if: left > right
1407 // -1 if: left < right
1408 switch (in_type) {
1409 case Primitive::kPrimLong: {
1410 Register result = OutputRegister(compare);
1411 Register left = InputRegisterAt(compare, 0);
1412 Operand right = InputOperandAt(compare, 1);
1413
1414 __ Cmp(left, right);
1415 __ Cset(result, ne);
1416 __ Cneg(result, result, lt);
1417 break;
1418 }
1419 case Primitive::kPrimFloat:
1420 case Primitive::kPrimDouble: {
1421 Register result = OutputRegister(compare);
1422 FPRegister left = InputFPRegisterAt(compare, 0);
1423 FPRegister right = InputFPRegisterAt(compare, 1);
1424
1425 __ Fcmp(left, right);
1426 if (compare->IsGtBias()) {
1427 __ Cset(result, ne);
1428 } else {
1429 __ Csetm(result, ne);
1430 }
1431 __ Cneg(result, result, compare->IsGtBias() ? mi : gt);
Alexandre Rames5319def2014-10-23 10:03:10 +01001432 break;
1433 }
1434 default:
1435 LOG(FATAL) << "Unimplemented compare type " << in_type;
1436 }
1437}
1438
1439void LocationsBuilderARM64::VisitCondition(HCondition* instruction) {
1440 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1441 locations->SetInAt(0, Location::RequiresRegister());
1442 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1443 if (instruction->NeedsMaterialization()) {
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001444 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001445 }
1446}
1447
1448void InstructionCodeGeneratorARM64::VisitCondition(HCondition* instruction) {
1449 if (!instruction->NeedsMaterialization()) {
1450 return;
1451 }
1452
1453 LocationSummary* locations = instruction->GetLocations();
1454 Register lhs = InputRegisterAt(instruction, 0);
1455 Operand rhs = InputOperandAt(instruction, 1);
1456 Register res = RegisterFrom(locations->Out(), instruction->GetType());
1457 Condition cond = ARM64Condition(instruction->GetCondition());
1458
1459 __ Cmp(lhs, rhs);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001460 __ Cset(res, cond);
Alexandre Rames5319def2014-10-23 10:03:10 +01001461}
1462
1463#define FOR_EACH_CONDITION_INSTRUCTION(M) \
1464 M(Equal) \
1465 M(NotEqual) \
1466 M(LessThan) \
1467 M(LessThanOrEqual) \
1468 M(GreaterThan) \
1469 M(GreaterThanOrEqual)
1470#define DEFINE_CONDITION_VISITORS(Name) \
1471void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } \
1472void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }
1473FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
Alexandre Rames67555f72014-11-18 10:55:16 +00001474#undef DEFINE_CONDITION_VISITORS
Alexandre Rames5319def2014-10-23 10:03:10 +01001475#undef FOR_EACH_CONDITION_INSTRUCTION
1476
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001477void LocationsBuilderARM64::VisitDiv(HDiv* div) {
1478 LocationSummary* locations =
1479 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
1480 switch (div->GetResultType()) {
1481 case Primitive::kPrimInt:
1482 case Primitive::kPrimLong:
1483 locations->SetInAt(0, Location::RequiresRegister());
1484 locations->SetInAt(1, Location::RequiresRegister());
1485 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1486 break;
1487
1488 case Primitive::kPrimFloat:
1489 case Primitive::kPrimDouble:
1490 locations->SetInAt(0, Location::RequiresFpuRegister());
1491 locations->SetInAt(1, Location::RequiresFpuRegister());
1492 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1493 break;
1494
1495 default:
1496 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1497 }
1498}
1499
1500void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
1501 Primitive::Type type = div->GetResultType();
1502 switch (type) {
1503 case Primitive::kPrimInt:
1504 case Primitive::kPrimLong:
1505 __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
1506 break;
1507
1508 case Primitive::kPrimFloat:
1509 case Primitive::kPrimDouble:
1510 __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
1511 break;
1512
1513 default:
1514 LOG(FATAL) << "Unexpected div type " << type;
1515 }
1516}
1517
Alexandre Rames67555f72014-11-18 10:55:16 +00001518void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1519 LocationSummary* locations =
1520 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1521 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
1522 if (instruction->HasUses()) {
1523 locations->SetOut(Location::SameAsFirstInput());
1524 }
1525}
1526
1527void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1528 SlowPathCodeARM64* slow_path =
1529 new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction);
1530 codegen_->AddSlowPath(slow_path);
1531 Location value = instruction->GetLocations()->InAt(0);
1532
Alexandre Rames3e69f162014-12-10 10:36:50 +00001533 Primitive::Type type = instruction->GetType();
1534
1535 if ((type != Primitive::kPrimInt) && (type != Primitive::kPrimLong)) {
1536 LOG(FATAL) << "Unexpected type " << type << "for DivZeroCheck.";
1537 return;
1538 }
1539
Alexandre Rames67555f72014-11-18 10:55:16 +00001540 if (value.IsConstant()) {
1541 int64_t divisor = Int64ConstantFrom(value);
1542 if (divisor == 0) {
1543 __ B(slow_path->GetEntryLabel());
1544 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +00001545 // A division by a non-null constant is valid. We don't need to perform
1546 // any check, so simply fall through.
Alexandre Rames67555f72014-11-18 10:55:16 +00001547 }
1548 } else {
1549 __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
1550 }
1551}
1552
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001553void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1554 LocationSummary* locations =
1555 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1556 locations->SetOut(Location::ConstantLocation(constant));
1557}
1558
1559void InstructionCodeGeneratorARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1560 UNUSED(constant);
1561 // Will be generated at use site.
1562}
1563
Alexandre Rames5319def2014-10-23 10:03:10 +01001564void LocationsBuilderARM64::VisitExit(HExit* exit) {
1565 exit->SetLocations(nullptr);
1566}
1567
1568void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001569 UNUSED(exit);
Alexandre Rames5319def2014-10-23 10:03:10 +01001570 if (kIsDebugBuild) {
1571 down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable");
Alexandre Rames67555f72014-11-18 10:55:16 +00001572 __ Brk(__LINE__); // TODO: Introduce special markers for such code locations.
Alexandre Rames5319def2014-10-23 10:03:10 +01001573 }
1574}
1575
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001576void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) {
1577 LocationSummary* locations =
1578 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1579 locations->SetOut(Location::ConstantLocation(constant));
1580}
1581
1582void InstructionCodeGeneratorARM64::VisitFloatConstant(HFloatConstant* constant) {
1583 UNUSED(constant);
1584 // Will be generated at use site.
1585}
1586
Alexandre Rames5319def2014-10-23 10:03:10 +01001587void LocationsBuilderARM64::VisitGoto(HGoto* got) {
1588 got->SetLocations(nullptr);
1589}
1590
1591void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
1592 HBasicBlock* successor = got->GetSuccessor();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001593 DCHECK(!successor->IsExitBlock());
1594 HBasicBlock* block = got->GetBlock();
1595 HInstruction* previous = got->GetPrevious();
1596 HLoopInformation* info = block->GetLoopInformation();
1597
1598 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
1599 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1600 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1601 return;
1602 }
1603 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1604 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1605 }
1606 if (!codegen_->GoesToNextBlock(block, successor)) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001607 __ B(codegen_->GetLabelOf(successor));
1608 }
1609}
1610
1611void LocationsBuilderARM64::VisitIf(HIf* if_instr) {
1612 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1613 HInstruction* cond = if_instr->InputAt(0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001614 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001615 locations->SetInAt(0, Location::RequiresRegister());
1616 }
1617}
1618
1619void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) {
1620 HInstruction* cond = if_instr->InputAt(0);
Alexandre Rames5319def2014-10-23 10:03:10 +01001621 HCondition* condition = cond->AsCondition();
1622 vixl::Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1623 vixl::Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1624
Serban Constantinescu02164b32014-11-13 14:05:07 +00001625 if (cond->IsIntConstant()) {
1626 int32_t cond_value = cond->AsIntConstant()->GetValue();
1627 if (cond_value == 1) {
1628 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
1629 __ B(true_target);
1630 }
1631 return;
1632 } else {
1633 DCHECK_EQ(cond_value, 0);
1634 }
1635 } else if (!cond->IsCondition() || condition->NeedsMaterialization()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001636 // The condition instruction has been materialized, compare the output to 0.
1637 Location cond_val = if_instr->GetLocations()->InAt(0);
1638 DCHECK(cond_val.IsRegister());
1639 __ Cbnz(InputRegisterAt(if_instr, 0), true_target);
Alexandre Rames5319def2014-10-23 10:03:10 +01001640 } else {
1641 // The condition instruction has not been materialized, use its inputs as
1642 // the comparison and its condition as the branch condition.
1643 Register lhs = InputRegisterAt(condition, 0);
1644 Operand rhs = InputOperandAt(condition, 1);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001645 Condition arm64_cond = ARM64Condition(condition->GetCondition());
1646 if ((arm64_cond == eq || arm64_cond == ne) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
1647 if (arm64_cond == eq) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001648 __ Cbz(lhs, true_target);
1649 } else {
1650 __ Cbnz(lhs, true_target);
1651 }
1652 } else {
1653 __ Cmp(lhs, rhs);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001654 __ B(arm64_cond, true_target);
Alexandre Rames5319def2014-10-23 10:03:10 +01001655 }
1656 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001657 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
1658 __ B(false_target);
1659 }
1660}
1661
1662void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1663 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1664 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001665 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001666}
1667
1668void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001669 MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset());
Alexandre Rames67555f72014-11-18 10:55:16 +00001670 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
Alexandre Rames5319def2014-10-23 10:03:10 +01001671}
1672
1673void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1674 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1675 locations->SetInAt(0, Location::RequiresRegister());
1676 locations->SetInAt(1, Location::RequiresRegister());
1677}
1678
1679void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001680 Primitive::Type field_type = instruction->GetFieldType();
Alexandre Rames67555f72014-11-18 10:55:16 +00001681 CPURegister value = InputCPURegisterAt(instruction, 1);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001682 Register obj = InputRegisterAt(instruction, 0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001683 codegen_->Store(field_type, value, HeapOperand(obj, instruction->GetFieldOffset()));
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001684 if (field_type == Primitive::kPrimNot) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001685 codegen_->MarkGCCard(obj, Register(value));
Alexandre Rames5319def2014-10-23 10:03:10 +01001686 }
1687}
1688
Alexandre Rames67555f72014-11-18 10:55:16 +00001689void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
1690 LocationSummary::CallKind call_kind =
1691 instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
1692 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
1693 locations->SetInAt(0, Location::RequiresRegister());
1694 locations->SetInAt(1, Location::RequiresRegister());
1695 locations->SetOut(Location::RequiresRegister(), true); // The output does overlap inputs.
1696}
1697
1698void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
1699 LocationSummary* locations = instruction->GetLocations();
1700 Register obj = InputRegisterAt(instruction, 0);;
1701 Register cls = InputRegisterAt(instruction, 1);;
1702 Register out = OutputRegister(instruction);
1703
1704 vixl::Label done;
1705
1706 // Return 0 if `obj` is null.
1707 // TODO: Avoid this check if we know `obj` is not null.
1708 __ Mov(out, 0);
1709 __ Cbz(obj, &done);
1710
1711 // Compare the class of `obj` with `cls`.
Serban Constantinescu02164b32014-11-13 14:05:07 +00001712 __ Ldr(out, HeapOperand(obj, mirror::Object::ClassOffset()));
Alexandre Rames67555f72014-11-18 10:55:16 +00001713 __ Cmp(out, cls);
1714 if (instruction->IsClassFinal()) {
1715 // Classes must be equal for the instanceof to succeed.
1716 __ Cset(out, eq);
1717 } else {
1718 // If the classes are not equal, we go into a slow path.
1719 DCHECK(locations->OnlyCallsOnSlowPath());
1720 SlowPathCodeARM64* slow_path =
Alexandre Rames3e69f162014-12-10 10:36:50 +00001721 new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(
1722 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Alexandre Rames67555f72014-11-18 10:55:16 +00001723 codegen_->AddSlowPath(slow_path);
1724 __ B(ne, slow_path->GetEntryLabel());
1725 __ Mov(out, 1);
1726 __ Bind(slow_path->GetExitLabel());
1727 }
1728
1729 __ Bind(&done);
1730}
1731
Alexandre Rames5319def2014-10-23 10:03:10 +01001732void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
1733 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1734 locations->SetOut(Location::ConstantLocation(constant));
1735}
1736
1737void InstructionCodeGeneratorARM64::VisitIntConstant(HIntConstant* constant) {
1738 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001739 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001740}
1741
Alexandre Rames5319def2014-10-23 10:03:10 +01001742void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
1743 LocationSummary* locations =
1744 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
1745 locations->AddTemp(LocationFrom(x0));
1746
1747 InvokeDexCallingConventionVisitor calling_convention_visitor;
1748 for (size_t i = 0; i < invoke->InputCount(); i++) {
1749 HInstruction* input = invoke->InputAt(i);
1750 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1751 }
1752
1753 Primitive::Type return_type = invoke->GetType();
1754 if (return_type != Primitive::kPrimVoid) {
1755 locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type));
1756 }
1757}
1758
Alexandre Rames67555f72014-11-18 10:55:16 +00001759void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1760 HandleInvoke(invoke);
1761}
1762
1763void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1764 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1765 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1766 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1767 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1768 Location receiver = invoke->GetLocations()->InAt(0);
1769 Offset class_offset = mirror::Object::ClassOffset();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001770 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
Alexandre Rames67555f72014-11-18 10:55:16 +00001771
1772 // The register ip1 is required to be used for the hidden argument in
1773 // art_quick_imt_conflict_trampoline, so prevent VIXL from using it.
1774 UseScratchRegisterScope scratch_scope(GetVIXLAssembler());
1775 scratch_scope.Exclude(ip1);
1776 __ Mov(ip1, invoke->GetDexMethodIndex());
1777
1778 // temp = object->GetClass();
1779 if (receiver.IsStackSlot()) {
1780 __ Ldr(temp, StackOperandFrom(receiver));
1781 __ Ldr(temp, HeapOperand(temp, class_offset));
1782 } else {
1783 __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
1784 }
1785 // temp = temp->GetImtEntryAt(method_offset);
1786 __ Ldr(temp, HeapOperand(temp, method_offset));
1787 // lr = temp->GetEntryPoint();
1788 __ Ldr(lr, HeapOperand(temp, entry_point));
1789 // lr();
1790 __ Blr(lr);
1791 DCHECK(!codegen_->IsLeafMethod());
1792 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1793}
1794
1795void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1796 HandleInvoke(invoke);
1797}
1798
1799void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
1800 HandleInvoke(invoke);
1801}
1802
Alexandre Rames5319def2014-10-23 10:03:10 +01001803void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
1804 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1805 // Make sure that ArtMethod* is passed in W0 as per the calling convention
1806 DCHECK(temp.Is(w0));
1807 size_t index_in_cache = mirror::Array::DataOffset(kHeapRefSize).SizeValue() +
1808 invoke->GetIndexInDexCache() * kHeapRefSize;
1809
1810 // TODO: Implement all kinds of calls:
1811 // 1) boot -> boot
1812 // 2) app -> boot
1813 // 3) app -> app
1814 //
1815 // Currently we implement the app -> app logic, which looks up in the resolve cache.
1816
1817 // temp = method;
Alexandre Rames67555f72014-11-18 10:55:16 +00001818 codegen_->LoadCurrentMethod(temp);
Alexandre Rames5319def2014-10-23 10:03:10 +01001819 // temp = temp->dex_cache_resolved_methods_;
Serban Constantinescu02164b32014-11-13 14:05:07 +00001820 __ Ldr(temp, HeapOperand(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset()));
Alexandre Rames5319def2014-10-23 10:03:10 +01001821 // temp = temp[index_in_cache];
Serban Constantinescu02164b32014-11-13 14:05:07 +00001822 __ Ldr(temp, HeapOperand(temp, index_in_cache));
Alexandre Rames5319def2014-10-23 10:03:10 +01001823 // lr = temp->entry_point_from_quick_compiled_code_;
Serban Constantinescu02164b32014-11-13 14:05:07 +00001824 __ Ldr(lr, HeapOperand(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
1825 kArm64WordSize)));
Alexandre Rames5319def2014-10-23 10:03:10 +01001826 // lr();
1827 __ Blr(lr);
1828
1829 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1830 DCHECK(!codegen_->IsLeafMethod());
1831}
1832
1833void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1834 LocationSummary* locations = invoke->GetLocations();
1835 Location receiver = locations->InAt(0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001836 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
Alexandre Rames5319def2014-10-23 10:03:10 +01001837 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1838 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1839 Offset class_offset = mirror::Object::ClassOffset();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001840 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
Alexandre Rames5319def2014-10-23 10:03:10 +01001841
1842 // temp = object->GetClass();
1843 if (receiver.IsStackSlot()) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001844 __ Ldr(temp, MemOperand(sp, receiver.GetStackIndex()));
1845 __ Ldr(temp, HeapOperand(temp, class_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001846 } else {
1847 DCHECK(receiver.IsRegister());
Serban Constantinescu02164b32014-11-13 14:05:07 +00001848 __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001849 }
1850 // temp = temp->GetMethodAt(method_offset);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001851 __ Ldr(temp, HeapOperand(temp, method_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001852 // lr = temp->GetEntryPoint();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001853 __ Ldr(lr, HeapOperand(temp, entry_point.SizeValue()));
Alexandre Rames5319def2014-10-23 10:03:10 +01001854 // lr();
1855 __ Blr(lr);
1856 DCHECK(!codegen_->IsLeafMethod());
1857 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1858}
1859
Alexandre Rames67555f72014-11-18 10:55:16 +00001860void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
1861 LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
1862 : LocationSummary::kNoCall;
1863 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
1864 locations->SetOut(Location::RequiresRegister());
1865}
1866
1867void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
1868 Register out = OutputRegister(cls);
1869 if (cls->IsReferrersClass()) {
1870 DCHECK(!cls->CanCallRuntime());
1871 DCHECK(!cls->MustGenerateClinitCheck());
1872 codegen_->LoadCurrentMethod(out);
1873 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
1874 } else {
1875 DCHECK(cls->CanCallRuntime());
1876 codegen_->LoadCurrentMethod(out);
1877 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset()));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001878 __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Alexandre Rames67555f72014-11-18 10:55:16 +00001879
1880 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
1881 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
1882 codegen_->AddSlowPath(slow_path);
1883 __ Cbz(out, slow_path->GetEntryLabel());
1884 if (cls->MustGenerateClinitCheck()) {
1885 GenerateClassInitializationCheck(slow_path, out);
1886 } else {
1887 __ Bind(slow_path->GetExitLabel());
1888 }
1889 }
1890}
1891
1892void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
1893 LocationSummary* locations =
1894 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
1895 locations->SetOut(Location::RequiresRegister());
1896}
1897
1898void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
1899 MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
1900 __ Ldr(OutputRegister(instruction), exception);
1901 __ Str(wzr, exception);
1902}
1903
Alexandre Rames5319def2014-10-23 10:03:10 +01001904void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
1905 load->SetLocations(nullptr);
1906}
1907
1908void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) {
1909 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001910 UNUSED(load);
Alexandre Rames5319def2014-10-23 10:03:10 +01001911}
1912
Alexandre Rames67555f72014-11-18 10:55:16 +00001913void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
1914 LocationSummary* locations =
1915 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
1916 locations->SetOut(Location::RequiresRegister());
1917}
1918
1919void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
1920 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
1921 codegen_->AddSlowPath(slow_path);
1922
1923 Register out = OutputRegister(load);
1924 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08001925 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
1926 __ Ldr(out, HeapOperand(out, mirror::Class::DexCacheStringsOffset()));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001927 __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Alexandre Rames67555f72014-11-18 10:55:16 +00001928 __ Cbz(out, slow_path->GetEntryLabel());
1929 __ Bind(slow_path->GetExitLabel());
1930}
1931
Alexandre Rames5319def2014-10-23 10:03:10 +01001932void LocationsBuilderARM64::VisitLocal(HLocal* local) {
1933 local->SetLocations(nullptr);
1934}
1935
1936void InstructionCodeGeneratorARM64::VisitLocal(HLocal* local) {
1937 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1938}
1939
1940void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
1941 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1942 locations->SetOut(Location::ConstantLocation(constant));
1943}
1944
1945void InstructionCodeGeneratorARM64::VisitLongConstant(HLongConstant* constant) {
1946 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001947 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001948}
1949
Alexandre Rames67555f72014-11-18 10:55:16 +00001950void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
1951 LocationSummary* locations =
1952 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1953 InvokeRuntimeCallingConvention calling_convention;
1954 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
1955}
1956
1957void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
1958 codegen_->InvokeRuntime(instruction->IsEnter()
1959 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
1960 instruction,
1961 instruction->GetDexPc());
1962}
1963
Alexandre Rames42d641b2014-10-27 14:00:51 +00001964void LocationsBuilderARM64::VisitMul(HMul* mul) {
1965 LocationSummary* locations =
1966 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1967 switch (mul->GetResultType()) {
1968 case Primitive::kPrimInt:
1969 case Primitive::kPrimLong:
1970 locations->SetInAt(0, Location::RequiresRegister());
1971 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001972 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00001973 break;
1974
1975 case Primitive::kPrimFloat:
1976 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001977 locations->SetInAt(0, Location::RequiresFpuRegister());
1978 locations->SetInAt(1, Location::RequiresFpuRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00001979 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00001980 break;
1981
1982 default:
1983 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1984 }
1985}
1986
1987void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) {
1988 switch (mul->GetResultType()) {
1989 case Primitive::kPrimInt:
1990 case Primitive::kPrimLong:
1991 __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
1992 break;
1993
1994 case Primitive::kPrimFloat:
1995 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001996 __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1));
Alexandre Rames42d641b2014-10-27 14:00:51 +00001997 break;
1998
1999 default:
2000 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2001 }
2002}
2003
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002004void LocationsBuilderARM64::VisitNeg(HNeg* neg) {
2005 LocationSummary* locations =
2006 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2007 switch (neg->GetResultType()) {
2008 case Primitive::kPrimInt:
Alexandre Rames67555f72014-11-18 10:55:16 +00002009 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002010 locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0)));
Alexandre Rames67555f72014-11-18 10:55:16 +00002011 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002012 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002013
2014 case Primitive::kPrimFloat:
2015 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +00002016 locations->SetInAt(0, Location::RequiresFpuRegister());
2017 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002018 break;
2019
2020 default:
2021 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2022 }
2023}
2024
2025void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
2026 switch (neg->GetResultType()) {
2027 case Primitive::kPrimInt:
2028 case Primitive::kPrimLong:
2029 __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
2030 break;
2031
2032 case Primitive::kPrimFloat:
2033 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +00002034 __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002035 break;
2036
2037 default:
2038 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2039 }
2040}
2041
2042void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) {
2043 LocationSummary* locations =
2044 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2045 InvokeRuntimeCallingConvention calling_convention;
2046 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
2047 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
2048 locations->SetOut(LocationFrom(x0));
2049 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(2)));
2050}
2051
2052void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
2053 LocationSummary* locations = instruction->GetLocations();
2054 InvokeRuntimeCallingConvention calling_convention;
2055 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
2056 DCHECK(type_index.Is(w0));
2057 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
2058 DCHECK(current_method.Is(w1));
Alexandre Rames67555f72014-11-18 10:55:16 +00002059 codegen_->LoadCurrentMethod(current_method);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002060 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +00002061 codegen_->InvokeRuntime(
2062 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002063}
2064
Alexandre Rames5319def2014-10-23 10:03:10 +01002065void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
2066 LocationSummary* locations =
2067 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2068 InvokeRuntimeCallingConvention calling_convention;
2069 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
2070 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
2071 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
2072}
2073
2074void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) {
2075 LocationSummary* locations = instruction->GetLocations();
2076 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
2077 DCHECK(type_index.Is(w0));
2078 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
2079 DCHECK(current_method.Is(w1));
Alexandre Rames67555f72014-11-18 10:55:16 +00002080 codegen_->LoadCurrentMethod(current_method);
Alexandre Rames5319def2014-10-23 10:03:10 +01002081 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +00002082 codegen_->InvokeRuntime(
2083 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
Alexandre Rames5319def2014-10-23 10:03:10 +01002084}
2085
2086void LocationsBuilderARM64::VisitNot(HNot* instruction) {
2087 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Alexandre Rames4e596512014-11-07 15:56:50 +00002088 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00002089 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01002090}
2091
2092void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
2093 switch (instruction->InputAt(0)->GetType()) {
2094 case Primitive::kPrimBoolean:
2095 __ Eor(OutputRegister(instruction), InputRegisterAt(instruction, 0), Operand(1));
2096 break;
2097
2098 case Primitive::kPrimInt:
Alexandre Rames5319def2014-10-23 10:03:10 +01002099 case Primitive::kPrimLong:
Roland Levillain55dcfb52014-10-24 18:09:09 +01002100 __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
Alexandre Rames5319def2014-10-23 10:03:10 +01002101 break;
2102
2103 default:
2104 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
2105 }
2106}
2107
2108void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
2109 LocationSummary* locations =
2110 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2111 locations->SetInAt(0, Location::RequiresRegister());
2112 if (instruction->HasUses()) {
2113 locations->SetOut(Location::SameAsFirstInput());
2114 }
2115}
2116
2117void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
2118 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction);
2119 codegen_->AddSlowPath(slow_path);
2120
2121 LocationSummary* locations = instruction->GetLocations();
2122 Location obj = locations->InAt(0);
2123 if (obj.IsRegister()) {
2124 __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel());
2125 } else {
2126 DCHECK(obj.IsConstant()) << obj;
2127 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
2128 __ B(slow_path->GetEntryLabel());
2129 }
2130}
2131
Alexandre Rames67555f72014-11-18 10:55:16 +00002132void LocationsBuilderARM64::VisitOr(HOr* instruction) {
2133 HandleBinaryOp(instruction);
2134}
2135
2136void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) {
2137 HandleBinaryOp(instruction);
2138}
2139
Alexandre Rames3e69f162014-12-10 10:36:50 +00002140void LocationsBuilderARM64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
2141 LOG(FATAL) << "Unreachable";
2142}
2143
2144void InstructionCodeGeneratorARM64::VisitParallelMove(HParallelMove* instruction) {
2145 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
2146}
2147
Alexandre Rames5319def2014-10-23 10:03:10 +01002148void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
2149 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2150 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2151 if (location.IsStackSlot()) {
2152 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2153 } else if (location.IsDoubleStackSlot()) {
2154 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2155 }
2156 locations->SetOut(location);
2157}
2158
2159void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) {
2160 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002161 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002162}
2163
2164void LocationsBuilderARM64::VisitPhi(HPhi* instruction) {
2165 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2166 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2167 locations->SetInAt(i, Location::Any());
2168 }
2169 locations->SetOut(Location::Any());
2170}
2171
2172void InstructionCodeGeneratorARM64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002173 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002174 LOG(FATAL) << "Unreachable";
2175}
2176
Serban Constantinescu02164b32014-11-13 14:05:07 +00002177void LocationsBuilderARM64::VisitRem(HRem* rem) {
2178 LocationSummary* locations =
2179 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
2180 switch (rem->GetResultType()) {
2181 case Primitive::kPrimInt:
2182 case Primitive::kPrimLong:
2183 locations->SetInAt(0, Location::RequiresRegister());
2184 locations->SetInAt(1, Location::RequiresRegister());
2185 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2186 break;
2187
2188 default:
2189 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
2190 }
2191}
2192
2193void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) {
2194 Primitive::Type type = rem->GetResultType();
2195 switch (type) {
2196 case Primitive::kPrimInt:
2197 case Primitive::kPrimLong: {
2198 UseScratchRegisterScope temps(GetVIXLAssembler());
2199 Register dividend = InputRegisterAt(rem, 0);
2200 Register divisor = InputRegisterAt(rem, 1);
2201 Register output = OutputRegister(rem);
2202 Register temp = temps.AcquireSameSizeAs(output);
2203
2204 __ Sdiv(temp, dividend, divisor);
2205 __ Msub(output, temp, divisor, dividend);
2206 break;
2207 }
2208
2209 default:
2210 LOG(FATAL) << "Unexpected rem type " << type;
2211 }
2212}
2213
Alexandre Rames5319def2014-10-23 10:03:10 +01002214void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
2215 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2216 Primitive::Type return_type = instruction->InputAt(0)->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002217 locations->SetInAt(0, ARM64ReturnLocation(return_type));
Alexandre Rames5319def2014-10-23 10:03:10 +01002218}
2219
2220void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002221 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002222 codegen_->GenerateFrameExit();
Alexandre Rames3e69f162014-12-10 10:36:50 +00002223 __ Ret();
Alexandre Rames5319def2014-10-23 10:03:10 +01002224}
2225
2226void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) {
2227 instruction->SetLocations(nullptr);
2228}
2229
2230void InstructionCodeGeneratorARM64::VisitReturnVoid(HReturnVoid* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002231 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002232 codegen_->GenerateFrameExit();
Alexandre Rames3e69f162014-12-10 10:36:50 +00002233 __ Ret();
Alexandre Rames5319def2014-10-23 10:03:10 +01002234}
2235
Serban Constantinescu02164b32014-11-13 14:05:07 +00002236void LocationsBuilderARM64::VisitShl(HShl* shl) {
2237 HandleShift(shl);
2238}
2239
2240void InstructionCodeGeneratorARM64::VisitShl(HShl* shl) {
2241 HandleShift(shl);
2242}
2243
2244void LocationsBuilderARM64::VisitShr(HShr* shr) {
2245 HandleShift(shr);
2246}
2247
2248void InstructionCodeGeneratorARM64::VisitShr(HShr* shr) {
2249 HandleShift(shr);
2250}
2251
Alexandre Rames5319def2014-10-23 10:03:10 +01002252void LocationsBuilderARM64::VisitStoreLocal(HStoreLocal* store) {
2253 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
2254 Primitive::Type field_type = store->InputAt(1)->GetType();
2255 switch (field_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002256 case Primitive::kPrimNot:
Alexandre Rames5319def2014-10-23 10:03:10 +01002257 case Primitive::kPrimBoolean:
2258 case Primitive::kPrimByte:
2259 case Primitive::kPrimChar:
2260 case Primitive::kPrimShort:
2261 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002262 case Primitive::kPrimFloat:
Alexandre Rames5319def2014-10-23 10:03:10 +01002263 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
2264 break;
2265
2266 case Primitive::kPrimLong:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002267 case Primitive::kPrimDouble:
Alexandre Rames5319def2014-10-23 10:03:10 +01002268 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
2269 break;
2270
2271 default:
2272 LOG(FATAL) << "Unimplemented local type " << field_type;
2273 }
2274}
2275
2276void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002277 UNUSED(store);
Alexandre Rames5319def2014-10-23 10:03:10 +01002278}
2279
2280void LocationsBuilderARM64::VisitSub(HSub* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002281 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002282}
2283
2284void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002285 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002286}
2287
Alexandre Rames67555f72014-11-18 10:55:16 +00002288void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2289 LocationSummary* locations =
2290 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2291 locations->SetInAt(0, Location::RequiresRegister());
2292 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2293}
2294
2295void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002296 MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset());
2297 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
Alexandre Rames67555f72014-11-18 10:55:16 +00002298}
2299
2300void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Alexandre Rames5319def2014-10-23 10:03:10 +01002301 LocationSummary* locations =
2302 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2303 locations->SetInAt(0, Location::RequiresRegister());
2304 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Rames5319def2014-10-23 10:03:10 +01002305}
2306
Alexandre Rames67555f72014-11-18 10:55:16 +00002307void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2308 CPURegister value = InputCPURegisterAt(instruction, 1);
2309 Register cls = InputRegisterAt(instruction, 0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00002310 Offset offset = instruction->GetFieldOffset();
Alexandre Rames67555f72014-11-18 10:55:16 +00002311 Primitive::Type field_type = instruction->GetFieldType();
Alexandre Rames5319def2014-10-23 10:03:10 +01002312
Serban Constantinescu02164b32014-11-13 14:05:07 +00002313 codegen_->Store(field_type, value, HeapOperand(cls, offset));
Alexandre Rames67555f72014-11-18 10:55:16 +00002314 if (field_type == Primitive::kPrimNot) {
2315 codegen_->MarkGCCard(cls, Register(value));
2316 }
Alexandre Rames5319def2014-10-23 10:03:10 +01002317}
2318
2319void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
2320 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
2321}
2322
2323void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002324 HBasicBlock* block = instruction->GetBlock();
2325 if (block->GetLoopInformation() != nullptr) {
2326 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
2327 // The back edge will generate the suspend check.
2328 return;
2329 }
2330 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
2331 // The goto will generate the suspend check.
2332 return;
2333 }
2334 GenerateSuspendCheck(instruction, nullptr);
Alexandre Rames5319def2014-10-23 10:03:10 +01002335}
2336
2337void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
2338 temp->SetLocations(nullptr);
2339}
2340
2341void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) {
2342 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002343 UNUSED(temp);
Alexandre Rames5319def2014-10-23 10:03:10 +01002344}
2345
Alexandre Rames67555f72014-11-18 10:55:16 +00002346void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
2347 LocationSummary* locations =
2348 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2349 InvokeRuntimeCallingConvention calling_convention;
2350 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2351}
2352
2353void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
2354 codegen_->InvokeRuntime(
2355 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
2356}
2357
2358void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
2359 LocationSummary* locations =
2360 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
2361 Primitive::Type input_type = conversion->GetInputType();
2362 Primitive::Type result_type = conversion->GetResultType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002363 DCHECK_NE(input_type, result_type);
Alexandre Rames67555f72014-11-18 10:55:16 +00002364 if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
2365 (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
2366 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
2367 }
2368
2369 if (IsFPType(input_type)) {
2370 locations->SetInAt(0, Location::RequiresFpuRegister());
2371 } else {
2372 locations->SetInAt(0, Location::RequiresRegister());
2373 }
2374
2375 if (IsFPType(result_type)) {
2376 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2377 } else {
2378 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2379 }
2380}
2381
2382void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
2383 Primitive::Type result_type = conversion->GetResultType();
2384 Primitive::Type input_type = conversion->GetInputType();
2385
2386 DCHECK_NE(input_type, result_type);
2387
2388 if (IsIntegralType(result_type) && IsIntegralType(input_type)) {
2389 int result_size = Primitive::ComponentSize(result_type);
2390 int input_size = Primitive::ComponentSize(input_type);
Alexandre Rames3e69f162014-12-10 10:36:50 +00002391 int min_size = std::min(result_size, input_size);
Serban Constantinescu02164b32014-11-13 14:05:07 +00002392 Register output = OutputRegister(conversion);
2393 Register source = InputRegisterAt(conversion, 0);
Alexandre Rames3e69f162014-12-10 10:36:50 +00002394 if ((result_type == Primitive::kPrimChar) && (input_size < result_size)) {
2395 __ Ubfx(output, source, 0, result_size * kBitsPerByte);
2396 } else if ((result_type == Primitive::kPrimChar) ||
2397 ((input_type == Primitive::kPrimChar) && (result_size > input_size))) {
2398 __ Ubfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
Alexandre Rames67555f72014-11-18 10:55:16 +00002399 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +00002400 __ Sbfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
Alexandre Rames67555f72014-11-18 10:55:16 +00002401 }
Serban Constantinescu02164b32014-11-13 14:05:07 +00002402 } else if (IsFPType(result_type) && IsIntegralType(input_type)) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002403 __ Scvtf(OutputFPRegister(conversion), InputRegisterAt(conversion, 0));
2404 } else if (IsIntegralType(result_type) && IsFPType(input_type)) {
2405 CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
2406 __ Fcvtzs(OutputRegister(conversion), InputFPRegisterAt(conversion, 0));
2407 } else if (IsFPType(result_type) && IsFPType(input_type)) {
2408 __ Fcvt(OutputFPRegister(conversion), InputFPRegisterAt(conversion, 0));
2409 } else {
2410 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
2411 << " to " << result_type;
Alexandre Rames67555f72014-11-18 10:55:16 +00002412 }
Serban Constantinescu02164b32014-11-13 14:05:07 +00002413}
Alexandre Rames67555f72014-11-18 10:55:16 +00002414
Serban Constantinescu02164b32014-11-13 14:05:07 +00002415void LocationsBuilderARM64::VisitUShr(HUShr* ushr) {
2416 HandleShift(ushr);
2417}
2418
2419void InstructionCodeGeneratorARM64::VisitUShr(HUShr* ushr) {
2420 HandleShift(ushr);
Alexandre Rames67555f72014-11-18 10:55:16 +00002421}
2422
2423void LocationsBuilderARM64::VisitXor(HXor* instruction) {
2424 HandleBinaryOp(instruction);
2425}
2426
2427void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) {
2428 HandleBinaryOp(instruction);
2429}
2430
2431#undef __
2432#undef QUICK_ENTRY_POINT
2433
Alexandre Rames5319def2014-10-23 10:03:10 +01002434} // namespace arm64
2435} // namespace art