blob: 21c1e9c5fcf894f90f316880992691040189e30d [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"
Andreas Gampe1cc7dba2014-12-17 18:43:01 -080020#include "entrypoints/quick/quick_entrypoints_enum.h"
Alexandre Rames5319def2014-10-23 10:03:10 +010021#include "gc/accounting/card_table.h"
22#include "mirror/array-inl.h"
23#include "mirror/art_method.h"
24#include "mirror/class.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000025#include "offsets.h"
Alexandre Rames5319def2014-10-23 10:03:10 +010026#include "thread.h"
27#include "utils/arm64/assembler_arm64.h"
28#include "utils/assembler.h"
29#include "utils/stack_checks.h"
30
31
32using namespace vixl; // NOLINT(build/namespaces)
33
34#ifdef __
35#error "ARM64 Codegen VIXL macro-assembler macro already defined."
36#endif
37
38
39namespace art {
40
41namespace arm64 {
42
Serban Constantinescu02d81cc2015-01-05 16:08:49 +000043// TODO: Tune the use of Load-Acquire, Store-Release vs Data Memory Barriers.
44// For now we prefer the use of load-acquire, store-release over explicit memory barriers.
45static constexpr bool kUseAcquireRelease = true;
Alexandre Rames5319def2014-10-23 10:03:10 +010046static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>);
47static constexpr int kCurrentMethodStackOffset = 0;
48
49namespace {
Alexandre Ramesa89086e2014-11-07 17:13:25 +000050
51bool IsFPType(Primitive::Type type) {
52 return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble;
53}
54
Alexandre Rames67555f72014-11-18 10:55:16 +000055bool IsIntegralType(Primitive::Type type) {
56 switch (type) {
57 case Primitive::kPrimByte:
58 case Primitive::kPrimChar:
59 case Primitive::kPrimShort:
60 case Primitive::kPrimInt:
61 case Primitive::kPrimLong:
62 return true;
63 default:
64 return false;
65 }
66}
67
Alexandre Ramesa89086e2014-11-07 17:13:25 +000068bool Is64BitType(Primitive::Type type) {
69 return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
70}
71
Alexandre Rames5319def2014-10-23 10:03:10 +010072// Convenience helpers to ease conversion to and from VIXL operands.
Alexandre Rames67555f72014-11-18 10:55:16 +000073static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32),
74 "Unexpected values for register codes.");
Alexandre Rames5319def2014-10-23 10:03:10 +010075
76int VIXLRegCodeFromART(int code) {
Alexandre Rames5319def2014-10-23 10:03:10 +010077 if (code == SP) {
78 return vixl::kSPRegInternalCode;
79 }
80 if (code == XZR) {
81 return vixl::kZeroRegCode;
82 }
83 return code;
84}
85
86int ARTRegCodeFromVIXL(int code) {
Alexandre Rames5319def2014-10-23 10:03:10 +010087 if (code == vixl::kSPRegInternalCode) {
88 return SP;
89 }
90 if (code == vixl::kZeroRegCode) {
91 return XZR;
92 }
93 return code;
94}
95
96Register XRegisterFrom(Location location) {
Alexandre Rames3e69f162014-12-10 10:36:50 +000097 DCHECK(location.IsRegister());
Alexandre Rames5319def2014-10-23 10:03:10 +010098 return Register::XRegFromCode(VIXLRegCodeFromART(location.reg()));
99}
100
101Register WRegisterFrom(Location location) {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000102 DCHECK(location.IsRegister());
Alexandre Rames5319def2014-10-23 10:03:10 +0100103 return Register::WRegFromCode(VIXLRegCodeFromART(location.reg()));
104}
105
106Register RegisterFrom(Location location, Primitive::Type type) {
107 DCHECK(type != Primitive::kPrimVoid && !IsFPType(type));
108 return type == Primitive::kPrimLong ? XRegisterFrom(location) : WRegisterFrom(location);
109}
110
111Register OutputRegister(HInstruction* instr) {
112 return RegisterFrom(instr->GetLocations()->Out(), instr->GetType());
113}
114
115Register InputRegisterAt(HInstruction* instr, int input_index) {
116 return RegisterFrom(instr->GetLocations()->InAt(input_index),
117 instr->InputAt(input_index)->GetType());
118}
119
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000120FPRegister DRegisterFrom(Location location) {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000121 DCHECK(location.IsFpuRegister());
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000122 return FPRegister::DRegFromCode(location.reg());
123}
124
125FPRegister SRegisterFrom(Location location) {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000126 DCHECK(location.IsFpuRegister());
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000127 return FPRegister::SRegFromCode(location.reg());
128}
129
130FPRegister FPRegisterFrom(Location location, Primitive::Type type) {
131 DCHECK(IsFPType(type));
132 return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location);
133}
134
135FPRegister OutputFPRegister(HInstruction* instr) {
136 return FPRegisterFrom(instr->GetLocations()->Out(), instr->GetType());
137}
138
139FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) {
140 return FPRegisterFrom(instr->GetLocations()->InAt(input_index),
141 instr->InputAt(input_index)->GetType());
142}
143
Alexandre Rames3e69f162014-12-10 10:36:50 +0000144CPURegister CPURegisterFrom(Location location, Primitive::Type type) {
145 return IsFPType(type) ? CPURegister(FPRegisterFrom(location, type))
146 : CPURegister(RegisterFrom(location, type));
147}
148
Alexandre Rames67555f72014-11-18 10:55:16 +0000149CPURegister OutputCPURegister(HInstruction* instr) {
150 return IsFPType(instr->GetType()) ? static_cast<CPURegister>(OutputFPRegister(instr))
151 : static_cast<CPURegister>(OutputRegister(instr));
152}
153
154CPURegister InputCPURegisterAt(HInstruction* instr, int index) {
155 return IsFPType(instr->InputAt(index)->GetType())
156 ? static_cast<CPURegister>(InputFPRegisterAt(instr, index))
157 : static_cast<CPURegister>(InputRegisterAt(instr, index));
158}
159
Alexandre Rames5319def2014-10-23 10:03:10 +0100160int64_t Int64ConstantFrom(Location location) {
161 HConstant* instr = location.GetConstant();
162 return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue()
163 : instr->AsLongConstant()->GetValue();
164}
165
166Operand OperandFrom(Location location, Primitive::Type type) {
167 if (location.IsRegister()) {
168 return Operand(RegisterFrom(location, type));
169 } else {
170 return Operand(Int64ConstantFrom(location));
171 }
172}
173
174Operand InputOperandAt(HInstruction* instr, int input_index) {
175 return OperandFrom(instr->GetLocations()->InAt(input_index),
176 instr->InputAt(input_index)->GetType());
177}
178
179MemOperand StackOperandFrom(Location location) {
180 return MemOperand(sp, location.GetStackIndex());
181}
182
Serban Constantinescu02164b32014-11-13 14:05:07 +0000183MemOperand HeapOperand(const Register& base, size_t offset = 0) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100184 // A heap reference must be 32bit, so fit in a W register.
185 DCHECK(base.IsW());
Alexandre Rames67555f72014-11-18 10:55:16 +0000186 return MemOperand(base.X(), offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100187}
188
Alexandre Rames67555f72014-11-18 10:55:16 +0000189MemOperand HeapOperand(const Register& base, Offset offset) {
190 return HeapOperand(base, offset.SizeValue());
191}
192
193MemOperand HeapOperandFrom(Location location, Offset offset) {
194 return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100195}
196
197Location LocationFrom(const Register& reg) {
198 return Location::RegisterLocation(ARTRegCodeFromVIXL(reg.code()));
199}
200
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000201Location LocationFrom(const FPRegister& fpreg) {
202 return Location::FpuRegisterLocation(fpreg.code());
203}
204
Alexandre Rames5319def2014-10-23 10:03:10 +0100205} // namespace
206
207inline Condition ARM64Condition(IfCondition cond) {
208 switch (cond) {
209 case kCondEQ: return eq;
210 case kCondNE: return ne;
211 case kCondLT: return lt;
212 case kCondLE: return le;
213 case kCondGT: return gt;
214 case kCondGE: return ge;
215 default:
216 LOG(FATAL) << "Unknown if condition";
217 }
218 return nv; // Unreachable.
219}
220
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000221Location ARM64ReturnLocation(Primitive::Type return_type) {
222 DCHECK_NE(return_type, Primitive::kPrimVoid);
223 // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the
224 // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`,
225 // but we use the exact registers for clarity.
226 if (return_type == Primitive::kPrimFloat) {
227 return LocationFrom(s0);
228 } else if (return_type == Primitive::kPrimDouble) {
229 return LocationFrom(d0);
230 } else if (return_type == Primitive::kPrimLong) {
231 return LocationFrom(x0);
232 } else {
233 return LocationFrom(w0);
234 }
235}
236
Alexandre Rames5319def2014-10-23 10:03:10 +0100237static const Register kRuntimeParameterCoreRegisters[] = { x0, x1, x2, x3, x4, x5, x6, x7 };
238static constexpr size_t kRuntimeParameterCoreRegistersLength =
239 arraysize(kRuntimeParameterCoreRegisters);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000240static const FPRegister kRuntimeParameterFpuRegisters[] = { d0, d1, d2, d3, d4, d5, d6, d7 };
241static constexpr size_t kRuntimeParameterFpuRegistersLength =
242 arraysize(kRuntimeParameterCoreRegisters);
Alexandre Rames5319def2014-10-23 10:03:10 +0100243
244class InvokeRuntimeCallingConvention : public CallingConvention<Register, FPRegister> {
245 public:
246 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
247
248 InvokeRuntimeCallingConvention()
249 : CallingConvention(kRuntimeParameterCoreRegisters,
250 kRuntimeParameterCoreRegistersLength,
251 kRuntimeParameterFpuRegisters,
252 kRuntimeParameterFpuRegistersLength) {}
253
254 Location GetReturnLocation(Primitive::Type return_type);
255
256 private:
257 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
258};
259
260Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type return_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000261 return ARM64ReturnLocation(return_type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100262}
263
Alexandre Rames67555f72014-11-18 10:55:16 +0000264#define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
265#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
Alexandre Rames5319def2014-10-23 10:03:10 +0100266
267class SlowPathCodeARM64 : public SlowPathCode {
268 public:
269 SlowPathCodeARM64() : entry_label_(), exit_label_() {}
270
271 vixl::Label* GetEntryLabel() { return &entry_label_; }
272 vixl::Label* GetExitLabel() { return &exit_label_; }
273
274 private:
275 vixl::Label entry_label_;
276 vixl::Label exit_label_;
277
278 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM64);
279};
280
281class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
282 public:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000283 BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
284 Location index_location,
285 Location length_location)
286 : instruction_(instruction),
287 index_location_(index_location),
288 length_location_(length_location) {}
289
Alexandre Rames5319def2014-10-23 10:03:10 +0100290
Alexandre Rames67555f72014-11-18 10:55:16 +0000291 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000292 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100293 __ Bind(GetEntryLabel());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000294 // We're moving two locations to locations that could overlap, so we need a parallel
295 // move resolver.
296 InvokeRuntimeCallingConvention calling_convention;
297 codegen->EmitParallelMoves(
298 index_location_, LocationFrom(calling_convention.GetRegisterAt(0)),
299 length_location_, LocationFrom(calling_convention.GetRegisterAt(1)));
300 arm64_codegen->InvokeRuntime(
301 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800302 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Alexandre Rames5319def2014-10-23 10:03:10 +0100303 }
304
305 private:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000306 HBoundsCheck* const instruction_;
307 const Location index_location_;
308 const Location length_location_;
309
Alexandre Rames5319def2014-10-23 10:03:10 +0100310 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
311};
312
Alexandre Rames67555f72014-11-18 10:55:16 +0000313class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 {
314 public:
315 explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : instruction_(instruction) {}
316
317 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
318 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
319 __ Bind(GetEntryLabel());
320 arm64_codegen->InvokeRuntime(
321 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800322 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Alexandre Rames67555f72014-11-18 10:55:16 +0000323 }
324
325 private:
326 HDivZeroCheck* const instruction_;
327 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64);
328};
329
330class LoadClassSlowPathARM64 : public SlowPathCodeARM64 {
331 public:
332 LoadClassSlowPathARM64(HLoadClass* cls,
333 HInstruction* at,
334 uint32_t dex_pc,
335 bool do_clinit)
336 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
337 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
338 }
339
340 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
341 LocationSummary* locations = at_->GetLocations();
342 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
343
344 __ Bind(GetEntryLabel());
345 codegen->SaveLiveRegisters(locations);
346
347 InvokeRuntimeCallingConvention calling_convention;
348 __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
349 arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W());
350 int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
351 : QUICK_ENTRY_POINT(pInitializeType);
352 arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800353 if (do_clinit_) {
354 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t, mirror::ArtMethod*>();
355 } else {
356 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t, mirror::ArtMethod*>();
357 }
Alexandre Rames67555f72014-11-18 10:55:16 +0000358
359 // Move the class to the desired location.
360 Location out = locations->Out();
361 if (out.IsValid()) {
362 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
363 Primitive::Type type = at_->GetType();
Alexandre Rames3e69f162014-12-10 10:36:50 +0000364 arm64_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
Alexandre Rames67555f72014-11-18 10:55:16 +0000365 }
366
367 codegen->RestoreLiveRegisters(locations);
368 __ B(GetExitLabel());
369 }
370
371 private:
372 // The class this slow path will load.
373 HLoadClass* const cls_;
374
375 // The instruction where this slow path is happening.
376 // (Might be the load class or an initialization check).
377 HInstruction* const at_;
378
379 // The dex PC of `at_`.
380 const uint32_t dex_pc_;
381
382 // Whether to initialize the class.
383 const bool do_clinit_;
384
385 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
386};
387
388class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
389 public:
390 explicit LoadStringSlowPathARM64(HLoadString* instruction) : instruction_(instruction) {}
391
392 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
393 LocationSummary* locations = instruction_->GetLocations();
394 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
395 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
396
397 __ Bind(GetEntryLabel());
398 codegen->SaveLiveRegisters(locations);
399
400 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800401 arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W());
402 __ Mov(calling_convention.GetRegisterAt(0).W(), instruction_->GetStringIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +0000403 arm64_codegen->InvokeRuntime(
404 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800405 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t, mirror::ArtMethod*>();
Alexandre Rames67555f72014-11-18 10:55:16 +0000406 Primitive::Type type = instruction_->GetType();
Alexandre Rames3e69f162014-12-10 10:36:50 +0000407 arm64_codegen->MoveLocation(locations->Out(), calling_convention.GetReturnLocation(type), type);
Alexandre Rames67555f72014-11-18 10:55:16 +0000408
409 codegen->RestoreLiveRegisters(locations);
410 __ B(GetExitLabel());
411 }
412
413 private:
414 HLoadString* const instruction_;
415
416 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
417};
418
Alexandre Rames5319def2014-10-23 10:03:10 +0100419class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
420 public:
421 explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {}
422
Alexandre Rames67555f72014-11-18 10:55:16 +0000423 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
424 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100425 __ Bind(GetEntryLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000426 arm64_codegen->InvokeRuntime(
427 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800428 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Alexandre Rames5319def2014-10-23 10:03:10 +0100429 }
430
431 private:
432 HNullCheck* const instruction_;
433
434 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM64);
435};
436
Serban Constantinescu02164b32014-11-13 14:05:07 +0000437class StackOverflowCheckSlowPathARM64 : public SlowPathCodeARM64 {
438 public:
439 StackOverflowCheckSlowPathARM64() {}
440
441 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
442 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
443 __ Bind(GetEntryLabel());
444 arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowStackOverflow), nullptr, 0);
Calin Juravle93edf732015-01-20 20:14:07 +0000445 CheckEntrypointTypes<kQuickThrowStackOverflow, void, void*>();
Serban Constantinescu02164b32014-11-13 14:05:07 +0000446 }
447
448 private:
449 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM64);
450};
451
Alexandre Rames5319def2014-10-23 10:03:10 +0100452class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 {
453 public:
454 explicit SuspendCheckSlowPathARM64(HSuspendCheck* instruction,
455 HBasicBlock* successor)
456 : instruction_(instruction), successor_(successor) {}
457
Alexandre Rames67555f72014-11-18 10:55:16 +0000458 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
459 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100460 __ Bind(GetEntryLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000461 codegen->SaveLiveRegisters(instruction_->GetLocations());
462 arm64_codegen->InvokeRuntime(
463 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800464 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Alexandre Rames67555f72014-11-18 10:55:16 +0000465 codegen->RestoreLiveRegisters(instruction_->GetLocations());
466 if (successor_ == nullptr) {
467 __ B(GetReturnLabel());
468 } else {
469 __ B(arm64_codegen->GetLabelOf(successor_));
470 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100471 }
472
473 vixl::Label* GetReturnLabel() {
474 DCHECK(successor_ == nullptr);
475 return &return_label_;
476 }
477
Alexandre Rames5319def2014-10-23 10:03:10 +0100478 private:
479 HSuspendCheck* const instruction_;
480 // If not null, the block to branch to after the suspend check.
481 HBasicBlock* const successor_;
482
483 // If `successor_` is null, the label to branch to after the suspend check.
484 vixl::Label return_label_;
485
486 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
487};
488
Alexandre Rames67555f72014-11-18 10:55:16 +0000489class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
490 public:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000491 TypeCheckSlowPathARM64(HInstruction* instruction,
492 Location class_to_check,
493 Location object_class,
494 uint32_t dex_pc)
495 : instruction_(instruction),
496 class_to_check_(class_to_check),
497 object_class_(object_class),
498 dex_pc_(dex_pc) {}
Alexandre Rames67555f72014-11-18 10:55:16 +0000499
500 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000501 LocationSummary* locations = instruction_->GetLocations();
502 DCHECK(instruction_->IsCheckCast()
503 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
504 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
505
Alexandre Rames67555f72014-11-18 10:55:16 +0000506 __ Bind(GetEntryLabel());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000507 codegen->SaveLiveRegisters(locations);
508
509 // We're moving two locations to locations that could overlap, so we need a parallel
510 // move resolver.
511 InvokeRuntimeCallingConvention calling_convention;
512 codegen->EmitParallelMoves(
513 class_to_check_, LocationFrom(calling_convention.GetRegisterAt(0)),
514 object_class_, LocationFrom(calling_convention.GetRegisterAt(1)));
515
516 if (instruction_->IsInstanceOf()) {
517 arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_);
518 Primitive::Type ret_type = instruction_->GetType();
519 Location ret_loc = calling_convention.GetReturnLocation(ret_type);
520 arm64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800521 CheckEntrypointTypes<kQuickInstanceofNonTrivial, uint32_t,
522 const mirror::Class*, const mirror::Class*>();
Alexandre Rames3e69f162014-12-10 10:36:50 +0000523 } else {
524 DCHECK(instruction_->IsCheckCast());
525 arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_);
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800526 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
Alexandre Rames3e69f162014-12-10 10:36:50 +0000527 }
528
529 codegen->RestoreLiveRegisters(locations);
Serban Constantinescu02164b32014-11-13 14:05:07 +0000530 __ B(GetExitLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000531 }
532
533 private:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000534 HInstruction* const instruction_;
535 const Location class_to_check_;
536 const Location object_class_;
537 uint32_t dex_pc_;
538
Alexandre Rames67555f72014-11-18 10:55:16 +0000539 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64);
540};
541
Alexandre Rames5319def2014-10-23 10:03:10 +0100542#undef __
543
544Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
545 Location next_location;
546 if (type == Primitive::kPrimVoid) {
547 LOG(FATAL) << "Unreachable type " << type;
548 }
549
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000550 if (IsFPType(type) && (fp_index_ < calling_convention.GetNumberOfFpuRegisters())) {
551 next_location = LocationFrom(calling_convention.GetFpuRegisterAt(fp_index_++));
552 } else if (!IsFPType(type) && (gp_index_ < calling_convention.GetNumberOfRegisters())) {
553 next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++));
554 } else {
555 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
556 next_location = Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
557 : Location::StackSlot(stack_offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100558 }
559
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000560 // Space on the stack is reserved for all arguments.
561 stack_index_ += Is64BitType(type) ? 2 : 1;
Alexandre Rames5319def2014-10-23 10:03:10 +0100562 return next_location;
563}
564
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000565CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph, const CompilerOptions& compiler_options)
Alexandre Rames5319def2014-10-23 10:03:10 +0100566 : CodeGenerator(graph,
567 kNumberOfAllocatableRegisters,
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000568 kNumberOfAllocatableFPRegisters,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000569 kNumberOfAllocatableRegisterPairs,
Nicolas Geoffray98893962015-01-21 12:32:32 +0000570 0,
571 0,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000572 compiler_options),
Alexandre Rames5319def2014-10-23 10:03:10 +0100573 block_labels_(nullptr),
574 location_builder_(graph, this),
Alexandre Rames3e69f162014-12-10 10:36:50 +0000575 instruction_visitor_(graph, this),
576 move_resolver_(graph->GetArena(), this) {}
Alexandre Rames5319def2014-10-23 10:03:10 +0100577
Alexandre Rames67555f72014-11-18 10:55:16 +0000578#undef __
579#define __ GetVIXLAssembler()->
Alexandre Rames5319def2014-10-23 10:03:10 +0100580
Serban Constantinescu32f5b4d2014-11-25 20:05:46 +0000581void CodeGeneratorARM64::Finalize(CodeAllocator* allocator) {
582 // Ensure we emit the literal pool.
583 __ FinalizeCode();
584 CodeGenerator::Finalize(allocator);
585}
586
Alexandre Rames3e69f162014-12-10 10:36:50 +0000587void ParallelMoveResolverARM64::EmitMove(size_t index) {
588 MoveOperands* move = moves_.Get(index);
589 codegen_->MoveLocation(move->GetDestination(), move->GetSource());
590}
591
592void ParallelMoveResolverARM64::EmitSwap(size_t index) {
593 MoveOperands* move = moves_.Get(index);
594 codegen_->SwapLocations(move->GetDestination(), move->GetSource());
595}
596
597void ParallelMoveResolverARM64::RestoreScratch(int reg) {
598 __ Pop(Register(VIXLRegCodeFromART(reg), kXRegSize));
599}
600
601void ParallelMoveResolverARM64::SpillScratch(int reg) {
602 __ Push(Register(VIXLRegCodeFromART(reg), kXRegSize));
603}
604
Alexandre Rames5319def2014-10-23 10:03:10 +0100605void CodeGeneratorARM64::GenerateFrameEntry() {
Serban Constantinescu02164b32014-11-13 14:05:07 +0000606 bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kArm64) || !IsLeafMethod();
607 if (do_overflow_check) {
608 UseScratchRegisterScope temps(GetVIXLAssembler());
609 Register temp = temps.AcquireX();
Calin Juravle93edf732015-01-20 20:14:07 +0000610 if (GetCompilerOptions().GetImplicitStackOverflowChecks()) {
611 __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
612 __ Ldr(wzr, MemOperand(temp, 0));
613 RecordPcInfo(nullptr, 0);
614 } else {
Serban Constantinescu02164b32014-11-13 14:05:07 +0000615 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM64();
616 AddSlowPath(slow_path);
617
618 __ Ldr(temp, MemOperand(tr, Thread::StackEndOffset<kArm64WordSize>().Int32Value()));
619 __ Cmp(sp, temp);
620 __ B(lo, slow_path->GetEntryLabel());
Serban Constantinescu02164b32014-11-13 14:05:07 +0000621 }
622 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100623
624 CPURegList preserved_regs = GetFramePreservedRegisters();
625 int frame_size = GetFrameSize();
626 core_spill_mask_ |= preserved_regs.list();
627
628 __ Str(w0, MemOperand(sp, -frame_size, PreIndex));
629 __ PokeCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
630
631 // Stack layout:
632 // sp[frame_size - 8] : lr.
633 // ... : other preserved registers.
634 // sp[frame_size - regs_size]: first preserved register.
635 // ... : reserved frame space.
Alexandre Rames67555f72014-11-18 10:55:16 +0000636 // sp[0] : current method.
Alexandre Rames5319def2014-10-23 10:03:10 +0100637}
638
639void CodeGeneratorARM64::GenerateFrameExit() {
640 int frame_size = GetFrameSize();
641 CPURegList preserved_regs = GetFramePreservedRegisters();
642 __ PeekCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
643 __ Drop(frame_size);
644}
645
646void CodeGeneratorARM64::Bind(HBasicBlock* block) {
647 __ Bind(GetLabelOf(block));
648}
649
Alexandre Rames5319def2014-10-23 10:03:10 +0100650void CodeGeneratorARM64::Move(HInstruction* instruction,
651 Location location,
652 HInstruction* move_for) {
653 LocationSummary* locations = instruction->GetLocations();
654 if (locations != nullptr && locations->Out().Equals(location)) {
655 return;
656 }
657
658 Primitive::Type type = instruction->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000659 DCHECK_NE(type, Primitive::kPrimVoid);
Alexandre Rames5319def2014-10-23 10:03:10 +0100660
661 if (instruction->IsIntConstant() || instruction->IsLongConstant()) {
662 int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue()
663 : instruction->AsLongConstant()->GetValue();
664 if (location.IsRegister()) {
665 Register dst = RegisterFrom(location, type);
666 DCHECK((instruction->IsIntConstant() && dst.Is32Bits()) ||
667 (instruction->IsLongConstant() && dst.Is64Bits()));
668 __ Mov(dst, value);
669 } else {
670 DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
Alexandre Rames67555f72014-11-18 10:55:16 +0000671 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100672 Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
673 __ Mov(temp, value);
674 __ Str(temp, StackOperandFrom(location));
675 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000676 } else if (instruction->IsTemporary()) {
677 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000678 MoveLocation(location, temp_location, type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100679 } else if (instruction->IsLoadLocal()) {
680 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000681 if (Is64BitType(type)) {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000682 MoveLocation(location, Location::DoubleStackSlot(stack_slot), type);
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000683 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000684 MoveLocation(location, Location::StackSlot(stack_slot), type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100685 }
686
687 } else {
688 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000689 MoveLocation(location, locations->Out(), type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100690 }
691}
692
693size_t CodeGeneratorARM64::FrameEntrySpillSize() const {
694 return GetFramePreservedRegistersSize();
695}
696
697Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const {
698 Primitive::Type type = load->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000699
Alexandre Rames5319def2014-10-23 10:03:10 +0100700 switch (type) {
701 case Primitive::kPrimNot:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000702 case Primitive::kPrimInt:
703 case Primitive::kPrimFloat:
704 return Location::StackSlot(GetStackSlot(load->GetLocal()));
705
706 case Primitive::kPrimLong:
707 case Primitive::kPrimDouble:
708 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
709
Alexandre Rames5319def2014-10-23 10:03:10 +0100710 case Primitive::kPrimBoolean:
711 case Primitive::kPrimByte:
712 case Primitive::kPrimChar:
713 case Primitive::kPrimShort:
Alexandre Rames5319def2014-10-23 10:03:10 +0100714 case Primitive::kPrimVoid:
Alexandre Rames5319def2014-10-23 10:03:10 +0100715 LOG(FATAL) << "Unexpected type " << type;
716 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000717
Alexandre Rames5319def2014-10-23 10:03:10 +0100718 LOG(FATAL) << "Unreachable";
719 return Location::NoLocation();
720}
721
722void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
Alexandre Rames67555f72014-11-18 10:55:16 +0000723 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100724 Register card = temps.AcquireX();
Serban Constantinescu02164b32014-11-13 14:05:07 +0000725 Register temp = temps.AcquireW(); // Index within the CardTable - 32bit.
Alexandre Rames5319def2014-10-23 10:03:10 +0100726 vixl::Label done;
727 __ Cbz(value, &done);
728 __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
729 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
Serban Constantinescu02164b32014-11-13 14:05:07 +0000730 __ Strb(card, MemOperand(card, temp.X()));
Alexandre Rames5319def2014-10-23 10:03:10 +0100731 __ Bind(&done);
732}
733
Nicolas Geoffray98893962015-01-21 12:32:32 +0000734void CodeGeneratorARM64::SetupBlockedRegisters(bool is_baseline ATTRIBUTE_UNUSED) const {
Alexandre Rames5319def2014-10-23 10:03:10 +0100735 // Block reserved registers:
736 // ip0 (VIXL temporary)
737 // ip1 (VIXL temporary)
Serban Constantinescu02164b32014-11-13 14:05:07 +0000738 // tr
Alexandre Rames5319def2014-10-23 10:03:10 +0100739 // lr
740 // sp is not part of the allocatable registers, so we don't need to block it.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000741 // TODO: Avoid blocking callee-saved registers, and instead preserve them
742 // where necessary.
Alexandre Rames5319def2014-10-23 10:03:10 +0100743 CPURegList reserved_core_registers = vixl_reserved_core_registers;
744 reserved_core_registers.Combine(runtime_reserved_core_registers);
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000745 reserved_core_registers.Combine(quick_callee_saved_registers);
Alexandre Rames5319def2014-10-23 10:03:10 +0100746 while (!reserved_core_registers.IsEmpty()) {
747 blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true;
748 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000749 CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
750 reserved_fp_registers.Combine(CPURegList::GetCalleeSavedFP());
751 while (!reserved_core_registers.IsEmpty()) {
752 blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().code()] = true;
753 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100754}
755
756Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const {
757 if (type == Primitive::kPrimVoid) {
758 LOG(FATAL) << "Unreachable type " << type;
759 }
760
Alexandre Rames5319def2014-10-23 10:03:10 +0100761 if (IsFPType(type)) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000762 ssize_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfAllocatableFPRegisters);
763 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100764 return Location::FpuRegisterLocation(reg);
765 } else {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000766 ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfAllocatableRegisters);
767 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100768 return Location::RegisterLocation(reg);
769 }
770}
771
Alexandre Rames3e69f162014-12-10 10:36:50 +0000772size_t CodeGeneratorARM64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
773 Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
774 __ Str(reg, MemOperand(sp, stack_index));
775 return kArm64WordSize;
776}
777
778size_t CodeGeneratorARM64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
779 Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
780 __ Ldr(reg, MemOperand(sp, stack_index));
781 return kArm64WordSize;
782}
783
784size_t CodeGeneratorARM64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
785 FPRegister reg = FPRegister(reg_id, kDRegSize);
786 __ Str(reg, MemOperand(sp, stack_index));
787 return kArm64WordSize;
788}
789
790size_t CodeGeneratorARM64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
791 FPRegister reg = FPRegister(reg_id, kDRegSize);
792 __ Ldr(reg, MemOperand(sp, stack_index));
793 return kArm64WordSize;
794}
795
Alexandre Rames5319def2014-10-23 10:03:10 +0100796void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
797 stream << Arm64ManagedRegister::FromXRegister(XRegister(reg));
798}
799
800void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
801 stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
802}
803
Alexandre Rames67555f72014-11-18 10:55:16 +0000804void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
805 if (constant->IsIntConstant() || constant->IsLongConstant()) {
806 __ Mov(Register(destination),
807 constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
808 : constant->AsLongConstant()->GetValue());
809 } else if (constant->IsFloatConstant()) {
810 __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
811 } else {
812 DCHECK(constant->IsDoubleConstant());
813 __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue());
814 }
815}
816
Alexandre Rames3e69f162014-12-10 10:36:50 +0000817
818static bool CoherentConstantAndType(Location constant, Primitive::Type type) {
819 DCHECK(constant.IsConstant());
820 HConstant* cst = constant.GetConstant();
821 return (cst->IsIntConstant() && type == Primitive::kPrimInt) ||
822 (cst->IsLongConstant() && type == Primitive::kPrimLong) ||
823 (cst->IsFloatConstant() && type == Primitive::kPrimFloat) ||
824 (cst->IsDoubleConstant() && type == Primitive::kPrimDouble);
825}
826
827void CodeGeneratorARM64::MoveLocation(Location destination, Location source, Primitive::Type type) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000828 if (source.Equals(destination)) {
829 return;
830 }
Alexandre Rames3e69f162014-12-10 10:36:50 +0000831
832 // A valid move can always be inferred from the destination and source
833 // locations. When moving from and to a register, the argument type can be
834 // used to generate 32bit instead of 64bit moves. In debug mode we also
835 // checks the coherency of the locations and the type.
836 bool unspecified_type = (type == Primitive::kPrimVoid);
837
838 if (destination.IsRegister() || destination.IsFpuRegister()) {
839 if (unspecified_type) {
840 HConstant* src_cst = source.IsConstant() ? source.GetConstant() : nullptr;
841 if (source.IsStackSlot() ||
842 (src_cst != nullptr && (src_cst->IsIntConstant() || src_cst->IsFloatConstant()))) {
843 // For stack slots and 32bit constants, a 64bit type is appropriate.
844 type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
Alexandre Rames67555f72014-11-18 10:55:16 +0000845 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000846 // If the source is a double stack slot or a 64bit constant, a 64bit
847 // type is appropriate. Else the source is a register, and since the
848 // type has not been specified, we chose a 64bit type to force a 64bit
849 // move.
850 type = destination.IsRegister() ? Primitive::kPrimLong : Primitive::kPrimDouble;
Alexandre Rames67555f72014-11-18 10:55:16 +0000851 }
Alexandre Rames3e69f162014-12-10 10:36:50 +0000852 }
853 DCHECK((destination.IsFpuRegister() && IsFPType(type)) ||
854 (destination.IsRegister() && !IsFPType(type)));
855 CPURegister dst = CPURegisterFrom(destination, type);
856 if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
857 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
858 __ Ldr(dst, StackOperandFrom(source));
859 } else if (source.IsConstant()) {
860 DCHECK(CoherentConstantAndType(source, type));
861 MoveConstant(dst, source.GetConstant());
862 } else {
863 if (destination.IsRegister()) {
864 __ Mov(Register(dst), RegisterFrom(source, type));
865 } else {
866 __ Fmov(FPRegister(dst), FPRegisterFrom(source, type));
867 }
868 }
869
870 } else { // The destination is not a register. It must be a stack slot.
871 DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
872 if (source.IsRegister() || source.IsFpuRegister()) {
873 if (unspecified_type) {
874 if (source.IsRegister()) {
875 type = destination.IsStackSlot() ? Primitive::kPrimInt : Primitive::kPrimLong;
876 } else {
877 type = destination.IsStackSlot() ? Primitive::kPrimFloat : Primitive::kPrimDouble;
878 }
879 }
880 DCHECK((destination.IsDoubleStackSlot() == Is64BitType(type)) &&
881 (source.IsFpuRegister() == IsFPType(type)));
882 __ Str(CPURegisterFrom(source, type), StackOperandFrom(destination));
883 } else if (source.IsConstant()) {
884 DCHECK(unspecified_type || CoherentConstantAndType(source, type));
885 UseScratchRegisterScope temps(GetVIXLAssembler());
886 HConstant* src_cst = source.GetConstant();
887 CPURegister temp;
888 if (src_cst->IsIntConstant()) {
889 temp = temps.AcquireW();
890 } else if (src_cst->IsLongConstant()) {
891 temp = temps.AcquireX();
892 } else if (src_cst->IsFloatConstant()) {
893 temp = temps.AcquireS();
894 } else {
895 DCHECK(src_cst->IsDoubleConstant());
896 temp = temps.AcquireD();
897 }
898 MoveConstant(temp, src_cst);
Alexandre Rames67555f72014-11-18 10:55:16 +0000899 __ Str(temp, StackOperandFrom(destination));
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000900 } else {
Alexandre Rames67555f72014-11-18 10:55:16 +0000901 DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000902 DCHECK(source.IsDoubleStackSlot() == destination.IsDoubleStackSlot());
Alexandre Rames67555f72014-11-18 10:55:16 +0000903 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000904 // There is generally less pressure on FP registers.
905 FPRegister temp = destination.IsDoubleStackSlot() ? temps.AcquireD() : temps.AcquireS();
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000906 __ Ldr(temp, StackOperandFrom(source));
907 __ Str(temp, StackOperandFrom(destination));
908 }
909 }
910}
911
Alexandre Rames3e69f162014-12-10 10:36:50 +0000912void CodeGeneratorARM64::SwapLocations(Location loc1, Location loc2) {
913 DCHECK(!loc1.IsConstant());
914 DCHECK(!loc2.IsConstant());
915
916 if (loc1.Equals(loc2)) {
917 return;
918 }
919
920 UseScratchRegisterScope temps(GetAssembler()->vixl_masm_);
921
922 bool is_slot1 = loc1.IsStackSlot() || loc1.IsDoubleStackSlot();
923 bool is_slot2 = loc2.IsStackSlot() || loc2.IsDoubleStackSlot();
924 bool is_fp_reg1 = loc1.IsFpuRegister();
925 bool is_fp_reg2 = loc2.IsFpuRegister();
926
927 if (loc2.IsRegister() && loc1.IsRegister()) {
928 Register r1 = XRegisterFrom(loc1);
929 Register r2 = XRegisterFrom(loc2);
930 Register tmp = temps.AcquireSameSizeAs(r1);
931 __ Mov(tmp, r2);
932 __ Mov(r2, r1);
933 __ Mov(r1, tmp);
934 } else if (is_fp_reg2 && is_fp_reg1) {
935 FPRegister r1 = DRegisterFrom(loc1);
936 FPRegister r2 = DRegisterFrom(loc2);
937 FPRegister tmp = temps.AcquireSameSizeAs(r1);
938 __ Fmov(tmp, r2);
939 __ Fmov(r2, r1);
940 __ Fmov(r1, tmp);
941 } else if (is_slot1 != is_slot2) {
942 MemOperand mem = StackOperandFrom(is_slot1 ? loc1 : loc2);
943 Location reg_loc = is_slot1 ? loc2 : loc1;
944 CPURegister reg, tmp;
945 if (reg_loc.IsFpuRegister()) {
946 reg = DRegisterFrom(reg_loc);
947 tmp = temps.AcquireD();
948 } else {
949 reg = XRegisterFrom(reg_loc);
950 tmp = temps.AcquireX();
951 }
952 __ Ldr(tmp, mem);
953 __ Str(reg, mem);
954 if (reg_loc.IsFpuRegister()) {
955 __ Fmov(FPRegister(reg), FPRegister(tmp));
956 } else {
957 __ Mov(Register(reg), Register(tmp));
958 }
959 } else if (is_slot1 && is_slot2) {
960 MemOperand mem1 = StackOperandFrom(loc1);
961 MemOperand mem2 = StackOperandFrom(loc2);
962 Register tmp1 = loc1.IsStackSlot() ? temps.AcquireW() : temps.AcquireX();
963 Register tmp2 = temps.AcquireSameSizeAs(tmp1);
964 __ Ldr(tmp1, mem1);
965 __ Ldr(tmp2, mem2);
966 __ Str(tmp1, mem2);
967 __ Str(tmp2, mem1);
968 } else {
969 LOG(FATAL) << "Unimplemented";
970 }
971}
972
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000973void CodeGeneratorARM64::Load(Primitive::Type type,
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000974 CPURegister dst,
975 const MemOperand& src) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000976 switch (type) {
977 case Primitive::kPrimBoolean:
Alexandre Rames67555f72014-11-18 10:55:16 +0000978 __ Ldrb(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000979 break;
980 case Primitive::kPrimByte:
Alexandre Rames67555f72014-11-18 10:55:16 +0000981 __ Ldrsb(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000982 break;
983 case Primitive::kPrimShort:
Alexandre Rames67555f72014-11-18 10:55:16 +0000984 __ Ldrsh(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000985 break;
986 case Primitive::kPrimChar:
Alexandre Rames67555f72014-11-18 10:55:16 +0000987 __ Ldrh(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000988 break;
989 case Primitive::kPrimInt:
990 case Primitive::kPrimNot:
991 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000992 case Primitive::kPrimFloat:
993 case Primitive::kPrimDouble:
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000994 DCHECK_EQ(dst.Is64Bits(), Is64BitType(type));
Alexandre Rames67555f72014-11-18 10:55:16 +0000995 __ Ldr(dst, src);
996 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000997 case Primitive::kPrimVoid:
998 LOG(FATAL) << "Unreachable type " << type;
999 }
1000}
1001
Calin Juravle77520bc2015-01-12 18:45:46 +00001002void CodeGeneratorARM64::LoadAcquire(HInstruction* instruction,
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001003 CPURegister dst,
1004 const MemOperand& src) {
1005 UseScratchRegisterScope temps(GetVIXLAssembler());
1006 Register temp_base = temps.AcquireX();
Calin Juravle77520bc2015-01-12 18:45:46 +00001007 Primitive::Type type = instruction->GetType();
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001008
1009 DCHECK(!src.IsRegisterOffset());
1010 DCHECK(!src.IsPreIndex());
1011 DCHECK(!src.IsPostIndex());
1012
1013 // TODO(vixl): Let the MacroAssembler handle MemOperand.
1014 __ Add(temp_base, src.base(), src.offset());
1015 MemOperand base = MemOperand(temp_base);
1016 switch (type) {
1017 case Primitive::kPrimBoolean:
1018 __ Ldarb(Register(dst), base);
Calin Juravle77520bc2015-01-12 18:45:46 +00001019 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001020 break;
1021 case Primitive::kPrimByte:
1022 __ Ldarb(Register(dst), base);
Calin Juravle77520bc2015-01-12 18:45:46 +00001023 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001024 __ Sbfx(Register(dst), Register(dst), 0, Primitive::ComponentSize(type) * kBitsPerByte);
1025 break;
1026 case Primitive::kPrimChar:
1027 __ Ldarh(Register(dst), base);
Calin Juravle77520bc2015-01-12 18:45:46 +00001028 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001029 break;
1030 case Primitive::kPrimShort:
1031 __ Ldarh(Register(dst), base);
Calin Juravle77520bc2015-01-12 18:45:46 +00001032 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001033 __ Sbfx(Register(dst), Register(dst), 0, Primitive::ComponentSize(type) * kBitsPerByte);
1034 break;
1035 case Primitive::kPrimInt:
1036 case Primitive::kPrimNot:
1037 case Primitive::kPrimLong:
1038 DCHECK_EQ(dst.Is64Bits(), Is64BitType(type));
1039 __ Ldar(Register(dst), base);
Calin Juravle77520bc2015-01-12 18:45:46 +00001040 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001041 break;
1042 case Primitive::kPrimFloat:
1043 case Primitive::kPrimDouble: {
1044 DCHECK(dst.IsFPRegister());
1045 DCHECK_EQ(dst.Is64Bits(), Is64BitType(type));
1046
1047 Register temp = dst.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
1048 __ Ldar(temp, base);
Calin Juravle77520bc2015-01-12 18:45:46 +00001049 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001050 __ Fmov(FPRegister(dst), temp);
1051 break;
1052 }
1053 case Primitive::kPrimVoid:
1054 LOG(FATAL) << "Unreachable type " << type;
1055 }
1056}
1057
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001058void CodeGeneratorARM64::Store(Primitive::Type type,
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001059 CPURegister src,
1060 const MemOperand& dst) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001061 switch (type) {
1062 case Primitive::kPrimBoolean:
1063 case Primitive::kPrimByte:
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001064 __ Strb(Register(src), dst);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001065 break;
1066 case Primitive::kPrimChar:
1067 case Primitive::kPrimShort:
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001068 __ Strh(Register(src), dst);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001069 break;
1070 case Primitive::kPrimInt:
1071 case Primitive::kPrimNot:
1072 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001073 case Primitive::kPrimFloat:
1074 case Primitive::kPrimDouble:
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001075 DCHECK_EQ(src.Is64Bits(), Is64BitType(type));
1076 __ Str(src, dst);
Alexandre Rames67555f72014-11-18 10:55:16 +00001077 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001078 case Primitive::kPrimVoid:
1079 LOG(FATAL) << "Unreachable type " << type;
1080 }
1081}
1082
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001083void CodeGeneratorARM64::StoreRelease(Primitive::Type type,
1084 CPURegister src,
1085 const MemOperand& dst) {
1086 UseScratchRegisterScope temps(GetVIXLAssembler());
1087 Register temp_base = temps.AcquireX();
1088
1089 DCHECK(!dst.IsRegisterOffset());
1090 DCHECK(!dst.IsPreIndex());
1091 DCHECK(!dst.IsPostIndex());
1092
1093 // TODO(vixl): Let the MacroAssembler handle this.
1094 __ Add(temp_base, dst.base(), dst.offset());
1095 MemOperand base = MemOperand(temp_base);
1096 switch (type) {
1097 case Primitive::kPrimBoolean:
1098 case Primitive::kPrimByte:
1099 __ Stlrb(Register(src), base);
1100 break;
1101 case Primitive::kPrimChar:
1102 case Primitive::kPrimShort:
1103 __ Stlrh(Register(src), base);
1104 break;
1105 case Primitive::kPrimInt:
1106 case Primitive::kPrimNot:
1107 case Primitive::kPrimLong:
1108 DCHECK_EQ(src.Is64Bits(), Is64BitType(type));
1109 __ Stlr(Register(src), base);
1110 break;
1111 case Primitive::kPrimFloat:
1112 case Primitive::kPrimDouble: {
1113 DCHECK(src.IsFPRegister());
1114 DCHECK_EQ(src.Is64Bits(), Is64BitType(type));
1115
1116 Register temp = src.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
1117 __ Fmov(temp, FPRegister(src));
1118 __ Stlr(temp, base);
1119 break;
1120 }
1121 case Primitive::kPrimVoid:
1122 LOG(FATAL) << "Unreachable type " << type;
1123 }
1124}
1125
Alexandre Rames67555f72014-11-18 10:55:16 +00001126void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) {
1127 DCHECK(current_method.IsW());
1128 __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
1129}
1130
1131void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
1132 HInstruction* instruction,
1133 uint32_t dex_pc) {
1134 __ Ldr(lr, MemOperand(tr, entry_point_offset));
1135 __ Blr(lr);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001136 if (instruction != nullptr) {
1137 RecordPcInfo(instruction, dex_pc);
1138 DCHECK(instruction->IsSuspendCheck()
1139 || instruction->IsBoundsCheck()
1140 || instruction->IsNullCheck()
1141 || instruction->IsDivZeroCheck()
1142 || !IsLeafMethod());
1143 }
Alexandre Rames67555f72014-11-18 10:55:16 +00001144}
1145
1146void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
1147 vixl::Register class_reg) {
1148 UseScratchRegisterScope temps(GetVIXLAssembler());
1149 Register temp = temps.AcquireW();
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001150 size_t status_offset = mirror::Class::StatusOffset().SizeValue();
1151
Serban Constantinescu02164b32014-11-13 14:05:07 +00001152 // Even if the initialized flag is set, we need to ensure consistent memory ordering.
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001153 if (kUseAcquireRelease) {
1154 // TODO(vixl): Let the MacroAssembler handle MemOperand.
1155 __ Add(temp, class_reg, status_offset);
1156 __ Ldar(temp, HeapOperand(temp));
1157 __ Cmp(temp, mirror::Class::kStatusInitialized);
1158 __ B(lt, slow_path->GetEntryLabel());
1159 } else {
1160 __ Ldr(temp, HeapOperand(class_reg, status_offset));
1161 __ Cmp(temp, mirror::Class::kStatusInitialized);
1162 __ B(lt, slow_path->GetEntryLabel());
1163 __ Dmb(InnerShareable, BarrierReads);
1164 }
Alexandre Rames67555f72014-11-18 10:55:16 +00001165 __ Bind(slow_path->GetExitLabel());
1166}
Alexandre Rames5319def2014-10-23 10:03:10 +01001167
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001168void InstructionCodeGeneratorARM64::GenerateMemoryBarrier(MemBarrierKind kind) {
1169 BarrierType type = BarrierAll;
1170
1171 switch (kind) {
1172 case MemBarrierKind::kAnyAny:
1173 case MemBarrierKind::kAnyStore: {
1174 type = BarrierAll;
1175 break;
1176 }
1177 case MemBarrierKind::kLoadAny: {
1178 type = BarrierReads;
1179 break;
1180 }
1181 case MemBarrierKind::kStoreStore: {
1182 type = BarrierWrites;
1183 break;
1184 }
1185 default:
1186 LOG(FATAL) << "Unexpected memory barrier " << kind;
1187 }
1188 __ Dmb(InnerShareable, type);
1189}
1190
Serban Constantinescu02164b32014-11-13 14:05:07 +00001191void InstructionCodeGeneratorARM64::GenerateSuspendCheck(HSuspendCheck* instruction,
1192 HBasicBlock* successor) {
1193 SuspendCheckSlowPathARM64* slow_path =
1194 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM64(instruction, successor);
1195 codegen_->AddSlowPath(slow_path);
1196 UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
1197 Register temp = temps.AcquireW();
1198
1199 __ Ldrh(temp, MemOperand(tr, Thread::ThreadFlagsOffset<kArm64WordSize>().SizeValue()));
1200 if (successor == nullptr) {
1201 __ Cbnz(temp, slow_path->GetEntryLabel());
1202 __ Bind(slow_path->GetReturnLabel());
1203 } else {
1204 __ Cbz(temp, codegen_->GetLabelOf(successor));
1205 __ B(slow_path->GetEntryLabel());
1206 // slow_path will return to GetLabelOf(successor).
1207 }
1208}
1209
Alexandre Rames5319def2014-10-23 10:03:10 +01001210InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
1211 CodeGeneratorARM64* codegen)
1212 : HGraphVisitor(graph),
1213 assembler_(codegen->GetAssembler()),
1214 codegen_(codegen) {}
1215
1216#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
Alexandre Rames3e69f162014-12-10 10:36:50 +00001217 /* No unimplemented IR. */
Alexandre Rames5319def2014-10-23 10:03:10 +01001218
1219#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
1220
1221enum UnimplementedInstructionBreakCode {
Alexandre Rames67555f72014-11-18 10:55:16 +00001222 // Using a base helps identify when we hit such breakpoints.
1223 UnimplementedInstructionBreakCodeBaseCode = 0x900,
Alexandre Rames5319def2014-10-23 10:03:10 +01001224#define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name),
1225 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION)
1226#undef ENUM_UNIMPLEMENTED_INSTRUCTION
1227};
1228
1229#define DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS(name) \
1230 void InstructionCodeGeneratorARM64::Visit##name(H##name* instr) { \
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001231 UNUSED(instr); \
Alexandre Rames5319def2014-10-23 10:03:10 +01001232 __ Brk(UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name)); \
1233 } \
1234 void LocationsBuilderARM64::Visit##name(H##name* instr) { \
1235 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); \
1236 locations->SetOut(Location::Any()); \
1237 }
1238 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS)
1239#undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS
1240
1241#undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE
Alexandre Rames67555f72014-11-18 10:55:16 +00001242#undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION
Alexandre Rames5319def2014-10-23 10:03:10 +01001243
Alexandre Rames67555f72014-11-18 10:55:16 +00001244void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001245 DCHECK_EQ(instr->InputCount(), 2U);
1246 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1247 Primitive::Type type = instr->GetResultType();
1248 switch (type) {
1249 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001250 case Primitive::kPrimLong:
Alexandre Rames5319def2014-10-23 10:03:10 +01001251 locations->SetInAt(0, Location::RequiresRegister());
1252 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001253 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001254 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001255
1256 case Primitive::kPrimFloat:
1257 case Primitive::kPrimDouble:
1258 locations->SetInAt(0, Location::RequiresFpuRegister());
1259 locations->SetInAt(1, Location::RequiresFpuRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00001260 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001261 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001262
Alexandre Rames5319def2014-10-23 10:03:10 +01001263 default:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001264 LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +01001265 }
1266}
1267
Alexandre Rames67555f72014-11-18 10:55:16 +00001268void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001269 Primitive::Type type = instr->GetType();
Alexandre Rames5319def2014-10-23 10:03:10 +01001270
1271 switch (type) {
1272 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001273 case Primitive::kPrimLong: {
1274 Register dst = OutputRegister(instr);
1275 Register lhs = InputRegisterAt(instr, 0);
1276 Operand rhs = InputOperandAt(instr, 1);
Alexandre Rames5319def2014-10-23 10:03:10 +01001277 if (instr->IsAdd()) {
1278 __ Add(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001279 } else if (instr->IsAnd()) {
1280 __ And(dst, lhs, rhs);
1281 } else if (instr->IsOr()) {
1282 __ Orr(dst, lhs, rhs);
1283 } else if (instr->IsSub()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001284 __ Sub(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001285 } else {
1286 DCHECK(instr->IsXor());
1287 __ Eor(dst, lhs, rhs);
Alexandre Rames5319def2014-10-23 10:03:10 +01001288 }
1289 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001290 }
1291 case Primitive::kPrimFloat:
1292 case Primitive::kPrimDouble: {
1293 FPRegister dst = OutputFPRegister(instr);
1294 FPRegister lhs = InputFPRegisterAt(instr, 0);
1295 FPRegister rhs = InputFPRegisterAt(instr, 1);
1296 if (instr->IsAdd()) {
1297 __ Fadd(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001298 } else if (instr->IsSub()) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001299 __ Fsub(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001300 } else {
1301 LOG(FATAL) << "Unexpected floating-point binary operation";
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001302 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001303 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001304 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001305 default:
Alexandre Rames67555f72014-11-18 10:55:16 +00001306 LOG(FATAL) << "Unexpected binary operation type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +01001307 }
1308}
1309
Serban Constantinescu02164b32014-11-13 14:05:07 +00001310void LocationsBuilderARM64::HandleShift(HBinaryOperation* instr) {
1311 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
1312
1313 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1314 Primitive::Type type = instr->GetResultType();
1315 switch (type) {
1316 case Primitive::kPrimInt:
1317 case Primitive::kPrimLong: {
1318 locations->SetInAt(0, Location::RequiresRegister());
1319 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1320 locations->SetOut(Location::RequiresRegister());
1321 break;
1322 }
1323 default:
1324 LOG(FATAL) << "Unexpected shift type " << type;
1325 }
1326}
1327
1328void InstructionCodeGeneratorARM64::HandleShift(HBinaryOperation* instr) {
1329 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
1330
1331 Primitive::Type type = instr->GetType();
1332 switch (type) {
1333 case Primitive::kPrimInt:
1334 case Primitive::kPrimLong: {
1335 Register dst = OutputRegister(instr);
1336 Register lhs = InputRegisterAt(instr, 0);
1337 Operand rhs = InputOperandAt(instr, 1);
1338 if (rhs.IsImmediate()) {
1339 uint32_t shift_value = (type == Primitive::kPrimInt)
1340 ? static_cast<uint32_t>(rhs.immediate() & kMaxIntShiftValue)
1341 : static_cast<uint32_t>(rhs.immediate() & kMaxLongShiftValue);
1342 if (instr->IsShl()) {
1343 __ Lsl(dst, lhs, shift_value);
1344 } else if (instr->IsShr()) {
1345 __ Asr(dst, lhs, shift_value);
1346 } else {
1347 __ Lsr(dst, lhs, shift_value);
1348 }
1349 } else {
1350 Register rhs_reg = dst.IsX() ? rhs.reg().X() : rhs.reg().W();
1351
1352 if (instr->IsShl()) {
1353 __ Lsl(dst, lhs, rhs_reg);
1354 } else if (instr->IsShr()) {
1355 __ Asr(dst, lhs, rhs_reg);
1356 } else {
1357 __ Lsr(dst, lhs, rhs_reg);
1358 }
1359 }
1360 break;
1361 }
1362 default:
1363 LOG(FATAL) << "Unexpected shift operation type " << type;
1364 }
1365}
1366
Alexandre Rames5319def2014-10-23 10:03:10 +01001367void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001368 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001369}
1370
1371void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001372 HandleBinaryOp(instruction);
1373}
1374
1375void LocationsBuilderARM64::VisitAnd(HAnd* instruction) {
1376 HandleBinaryOp(instruction);
1377}
1378
1379void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) {
1380 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001381}
1382
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001383void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
1384 LocationSummary* locations =
1385 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1386 locations->SetInAt(0, Location::RequiresRegister());
1387 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1388 locations->SetOut(Location::RequiresRegister());
1389}
1390
1391void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
1392 LocationSummary* locations = instruction->GetLocations();
1393 Primitive::Type type = instruction->GetType();
1394 Register obj = InputRegisterAt(instruction, 0);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001395 Location index = locations->InAt(1);
1396 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001397 MemOperand source = HeapOperand(obj);
Alexandre Rames67555f72014-11-18 10:55:16 +00001398 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001399
1400 if (index.IsConstant()) {
1401 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001402 source = HeapOperand(obj, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001403 } else {
1404 Register temp = temps.AcquireSameSizeAs(obj);
1405 Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
1406 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type)));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001407 source = HeapOperand(temp, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001408 }
1409
Alexandre Rames67555f72014-11-18 10:55:16 +00001410 codegen_->Load(type, OutputCPURegister(instruction), source);
Calin Juravle77520bc2015-01-12 18:45:46 +00001411 codegen_->MaybeRecordImplicitNullCheck(instruction);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001412}
1413
Alexandre Rames5319def2014-10-23 10:03:10 +01001414void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
1415 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1416 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001417 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001418}
1419
1420void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
1421 __ Ldr(OutputRegister(instruction),
1422 HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset()));
Calin Juravle77520bc2015-01-12 18:45:46 +00001423 codegen_->MaybeRecordImplicitNullCheck(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001424}
1425
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001426void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
1427 Primitive::Type value_type = instruction->GetComponentType();
1428 bool is_object = value_type == Primitive::kPrimNot;
1429 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1430 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1431 if (is_object) {
1432 InvokeRuntimeCallingConvention calling_convention;
1433 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
1434 locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
1435 locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
1436 } else {
1437 locations->SetInAt(0, Location::RequiresRegister());
1438 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1439 locations->SetInAt(2, Location::RequiresRegister());
1440 }
1441}
1442
1443void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
1444 Primitive::Type value_type = instruction->GetComponentType();
1445 if (value_type == Primitive::kPrimNot) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001446 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08001447 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001448 } else {
1449 LocationSummary* locations = instruction->GetLocations();
1450 Register obj = InputRegisterAt(instruction, 0);
Alexandre Rames67555f72014-11-18 10:55:16 +00001451 CPURegister value = InputCPURegisterAt(instruction, 2);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001452 Location index = locations->InAt(1);
1453 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001454 MemOperand destination = HeapOperand(obj);
Alexandre Rames67555f72014-11-18 10:55:16 +00001455 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001456
1457 if (index.IsConstant()) {
1458 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001459 destination = HeapOperand(obj, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001460 } else {
1461 Register temp = temps.AcquireSameSizeAs(obj);
1462 Register index_reg = InputRegisterAt(instruction, 1);
1463 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type)));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001464 destination = HeapOperand(temp, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001465 }
1466
1467 codegen_->Store(value_type, value, destination);
Calin Juravle77520bc2015-01-12 18:45:46 +00001468 codegen_->MaybeRecordImplicitNullCheck(instruction);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001469 }
1470}
1471
Alexandre Rames67555f72014-11-18 10:55:16 +00001472void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1473 LocationSummary* locations =
1474 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1475 locations->SetInAt(0, Location::RequiresRegister());
1476 locations->SetInAt(1, Location::RequiresRegister());
1477 if (instruction->HasUses()) {
1478 locations->SetOut(Location::SameAsFirstInput());
1479 }
1480}
1481
1482void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
Alexandre Rames3e69f162014-12-10 10:36:50 +00001483 LocationSummary* locations = instruction->GetLocations();
1484 BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(
1485 instruction, locations->InAt(0), locations->InAt(1));
Alexandre Rames67555f72014-11-18 10:55:16 +00001486 codegen_->AddSlowPath(slow_path);
1487
1488 __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
1489 __ B(slow_path->GetEntryLabel(), hs);
1490}
1491
1492void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
1493 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1494 instruction, LocationSummary::kCallOnSlowPath);
1495 locations->SetInAt(0, Location::RequiresRegister());
1496 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Rames3e69f162014-12-10 10:36:50 +00001497 locations->AddTemp(Location::RequiresRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00001498}
1499
1500void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
Alexandre Rames3e69f162014-12-10 10:36:50 +00001501 LocationSummary* locations = instruction->GetLocations();
Alexandre Rames67555f72014-11-18 10:55:16 +00001502 Register obj = InputRegisterAt(instruction, 0);;
1503 Register cls = InputRegisterAt(instruction, 1);;
Alexandre Rames3e69f162014-12-10 10:36:50 +00001504 Register obj_cls = WRegisterFrom(instruction->GetLocations()->GetTemp(0));
Alexandre Rames67555f72014-11-18 10:55:16 +00001505
Alexandre Rames3e69f162014-12-10 10:36:50 +00001506 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(
1507 instruction, locations->InAt(1), LocationFrom(obj_cls), instruction->GetDexPc());
Alexandre Rames67555f72014-11-18 10:55:16 +00001508 codegen_->AddSlowPath(slow_path);
1509
1510 // TODO: avoid this check if we know obj is not null.
1511 __ Cbz(obj, slow_path->GetExitLabel());
1512 // Compare the class of `obj` with `cls`.
Alexandre Rames3e69f162014-12-10 10:36:50 +00001513 __ Ldr(obj_cls, HeapOperand(obj, mirror::Object::ClassOffset()));
1514 __ Cmp(obj_cls, cls);
Alexandre Rames67555f72014-11-18 10:55:16 +00001515 __ B(ne, slow_path->GetEntryLabel());
1516 __ Bind(slow_path->GetExitLabel());
1517}
1518
1519void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) {
1520 LocationSummary* locations =
1521 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
1522 locations->SetInAt(0, Location::RequiresRegister());
1523 if (check->HasUses()) {
1524 locations->SetOut(Location::SameAsFirstInput());
1525 }
1526}
1527
1528void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) {
1529 // We assume the class is not null.
1530 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
1531 check->GetLoadClass(), check, check->GetDexPc(), true);
1532 codegen_->AddSlowPath(slow_path);
1533 GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
1534}
1535
Serban Constantinescu02164b32014-11-13 14:05:07 +00001536void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001537 LocationSummary* locations =
Serban Constantinescu02164b32014-11-13 14:05:07 +00001538 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
1539 Primitive::Type in_type = compare->InputAt(0)->GetType();
Alexandre Rames5319def2014-10-23 10:03:10 +01001540 switch (in_type) {
1541 case Primitive::kPrimLong: {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001542 locations->SetInAt(0, Location::RequiresRegister());
1543 locations->SetInAt(1, Location::RegisterOrConstant(compare->InputAt(1)));
1544 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1545 break;
1546 }
1547 case Primitive::kPrimFloat:
1548 case Primitive::kPrimDouble: {
1549 locations->SetInAt(0, Location::RequiresFpuRegister());
1550 locations->SetInAt(1, Location::RequiresFpuRegister());
1551 locations->SetOut(Location::RequiresRegister());
1552 break;
1553 }
1554 default:
1555 LOG(FATAL) << "Unexpected type for compare operation " << in_type;
1556 }
1557}
1558
1559void InstructionCodeGeneratorARM64::VisitCompare(HCompare* compare) {
1560 Primitive::Type in_type = compare->InputAt(0)->GetType();
1561
1562 // 0 if: left == right
1563 // 1 if: left > right
1564 // -1 if: left < right
1565 switch (in_type) {
1566 case Primitive::kPrimLong: {
1567 Register result = OutputRegister(compare);
1568 Register left = InputRegisterAt(compare, 0);
1569 Operand right = InputOperandAt(compare, 1);
1570
1571 __ Cmp(left, right);
1572 __ Cset(result, ne);
1573 __ Cneg(result, result, lt);
1574 break;
1575 }
1576 case Primitive::kPrimFloat:
1577 case Primitive::kPrimDouble: {
1578 Register result = OutputRegister(compare);
1579 FPRegister left = InputFPRegisterAt(compare, 0);
1580 FPRegister right = InputFPRegisterAt(compare, 1);
1581
1582 __ Fcmp(left, right);
1583 if (compare->IsGtBias()) {
1584 __ Cset(result, ne);
1585 } else {
1586 __ Csetm(result, ne);
1587 }
1588 __ Cneg(result, result, compare->IsGtBias() ? mi : gt);
Alexandre Rames5319def2014-10-23 10:03:10 +01001589 break;
1590 }
1591 default:
1592 LOG(FATAL) << "Unimplemented compare type " << in_type;
1593 }
1594}
1595
1596void LocationsBuilderARM64::VisitCondition(HCondition* instruction) {
1597 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1598 locations->SetInAt(0, Location::RequiresRegister());
1599 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1600 if (instruction->NeedsMaterialization()) {
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001601 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001602 }
1603}
1604
1605void InstructionCodeGeneratorARM64::VisitCondition(HCondition* instruction) {
1606 if (!instruction->NeedsMaterialization()) {
1607 return;
1608 }
1609
1610 LocationSummary* locations = instruction->GetLocations();
1611 Register lhs = InputRegisterAt(instruction, 0);
1612 Operand rhs = InputOperandAt(instruction, 1);
1613 Register res = RegisterFrom(locations->Out(), instruction->GetType());
1614 Condition cond = ARM64Condition(instruction->GetCondition());
1615
1616 __ Cmp(lhs, rhs);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001617 __ Cset(res, cond);
Alexandre Rames5319def2014-10-23 10:03:10 +01001618}
1619
1620#define FOR_EACH_CONDITION_INSTRUCTION(M) \
1621 M(Equal) \
1622 M(NotEqual) \
1623 M(LessThan) \
1624 M(LessThanOrEqual) \
1625 M(GreaterThan) \
1626 M(GreaterThanOrEqual)
1627#define DEFINE_CONDITION_VISITORS(Name) \
1628void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } \
1629void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }
1630FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
Alexandre Rames67555f72014-11-18 10:55:16 +00001631#undef DEFINE_CONDITION_VISITORS
Alexandre Rames5319def2014-10-23 10:03:10 +01001632#undef FOR_EACH_CONDITION_INSTRUCTION
1633
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001634void LocationsBuilderARM64::VisitDiv(HDiv* div) {
1635 LocationSummary* locations =
1636 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
1637 switch (div->GetResultType()) {
1638 case Primitive::kPrimInt:
1639 case Primitive::kPrimLong:
1640 locations->SetInAt(0, Location::RequiresRegister());
1641 locations->SetInAt(1, Location::RequiresRegister());
1642 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1643 break;
1644
1645 case Primitive::kPrimFloat:
1646 case Primitive::kPrimDouble:
1647 locations->SetInAt(0, Location::RequiresFpuRegister());
1648 locations->SetInAt(1, Location::RequiresFpuRegister());
1649 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1650 break;
1651
1652 default:
1653 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1654 }
1655}
1656
1657void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
1658 Primitive::Type type = div->GetResultType();
1659 switch (type) {
1660 case Primitive::kPrimInt:
1661 case Primitive::kPrimLong:
1662 __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
1663 break;
1664
1665 case Primitive::kPrimFloat:
1666 case Primitive::kPrimDouble:
1667 __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
1668 break;
1669
1670 default:
1671 LOG(FATAL) << "Unexpected div type " << type;
1672 }
1673}
1674
Alexandre Rames67555f72014-11-18 10:55:16 +00001675void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1676 LocationSummary* locations =
1677 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1678 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
1679 if (instruction->HasUses()) {
1680 locations->SetOut(Location::SameAsFirstInput());
1681 }
1682}
1683
1684void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1685 SlowPathCodeARM64* slow_path =
1686 new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction);
1687 codegen_->AddSlowPath(slow_path);
1688 Location value = instruction->GetLocations()->InAt(0);
1689
Alexandre Rames3e69f162014-12-10 10:36:50 +00001690 Primitive::Type type = instruction->GetType();
1691
1692 if ((type != Primitive::kPrimInt) && (type != Primitive::kPrimLong)) {
1693 LOG(FATAL) << "Unexpected type " << type << "for DivZeroCheck.";
1694 return;
1695 }
1696
Alexandre Rames67555f72014-11-18 10:55:16 +00001697 if (value.IsConstant()) {
1698 int64_t divisor = Int64ConstantFrom(value);
1699 if (divisor == 0) {
1700 __ B(slow_path->GetEntryLabel());
1701 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +00001702 // A division by a non-null constant is valid. We don't need to perform
1703 // any check, so simply fall through.
Alexandre Rames67555f72014-11-18 10:55:16 +00001704 }
1705 } else {
1706 __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
1707 }
1708}
1709
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001710void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1711 LocationSummary* locations =
1712 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1713 locations->SetOut(Location::ConstantLocation(constant));
1714}
1715
1716void InstructionCodeGeneratorARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1717 UNUSED(constant);
1718 // Will be generated at use site.
1719}
1720
Alexandre Rames5319def2014-10-23 10:03:10 +01001721void LocationsBuilderARM64::VisitExit(HExit* exit) {
1722 exit->SetLocations(nullptr);
1723}
1724
1725void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001726 UNUSED(exit);
Alexandre Rames5319def2014-10-23 10:03:10 +01001727 if (kIsDebugBuild) {
1728 down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable");
Alexandre Rames67555f72014-11-18 10:55:16 +00001729 __ Brk(__LINE__); // TODO: Introduce special markers for such code locations.
Alexandre Rames5319def2014-10-23 10:03:10 +01001730 }
1731}
1732
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001733void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) {
1734 LocationSummary* locations =
1735 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1736 locations->SetOut(Location::ConstantLocation(constant));
1737}
1738
1739void InstructionCodeGeneratorARM64::VisitFloatConstant(HFloatConstant* constant) {
1740 UNUSED(constant);
1741 // Will be generated at use site.
1742}
1743
Alexandre Rames5319def2014-10-23 10:03:10 +01001744void LocationsBuilderARM64::VisitGoto(HGoto* got) {
1745 got->SetLocations(nullptr);
1746}
1747
1748void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
1749 HBasicBlock* successor = got->GetSuccessor();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001750 DCHECK(!successor->IsExitBlock());
1751 HBasicBlock* block = got->GetBlock();
1752 HInstruction* previous = got->GetPrevious();
1753 HLoopInformation* info = block->GetLoopInformation();
1754
1755 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
1756 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1757 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1758 return;
1759 }
1760 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1761 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1762 }
1763 if (!codegen_->GoesToNextBlock(block, successor)) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001764 __ B(codegen_->GetLabelOf(successor));
1765 }
1766}
1767
1768void LocationsBuilderARM64::VisitIf(HIf* if_instr) {
1769 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1770 HInstruction* cond = if_instr->InputAt(0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001771 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001772 locations->SetInAt(0, Location::RequiresRegister());
1773 }
1774}
1775
1776void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) {
1777 HInstruction* cond = if_instr->InputAt(0);
Alexandre Rames5319def2014-10-23 10:03:10 +01001778 HCondition* condition = cond->AsCondition();
1779 vixl::Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1780 vixl::Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1781
Serban Constantinescu02164b32014-11-13 14:05:07 +00001782 if (cond->IsIntConstant()) {
1783 int32_t cond_value = cond->AsIntConstant()->GetValue();
1784 if (cond_value == 1) {
1785 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
1786 __ B(true_target);
1787 }
1788 return;
1789 } else {
1790 DCHECK_EQ(cond_value, 0);
1791 }
1792 } else if (!cond->IsCondition() || condition->NeedsMaterialization()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001793 // The condition instruction has been materialized, compare the output to 0.
1794 Location cond_val = if_instr->GetLocations()->InAt(0);
1795 DCHECK(cond_val.IsRegister());
1796 __ Cbnz(InputRegisterAt(if_instr, 0), true_target);
Alexandre Rames5319def2014-10-23 10:03:10 +01001797 } else {
1798 // The condition instruction has not been materialized, use its inputs as
1799 // the comparison and its condition as the branch condition.
1800 Register lhs = InputRegisterAt(condition, 0);
1801 Operand rhs = InputOperandAt(condition, 1);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001802 Condition arm64_cond = ARM64Condition(condition->GetCondition());
1803 if ((arm64_cond == eq || arm64_cond == ne) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
1804 if (arm64_cond == eq) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001805 __ Cbz(lhs, true_target);
1806 } else {
1807 __ Cbnz(lhs, true_target);
1808 }
1809 } else {
1810 __ Cmp(lhs, rhs);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001811 __ B(arm64_cond, true_target);
Alexandre Rames5319def2014-10-23 10:03:10 +01001812 }
1813 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001814 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
1815 __ B(false_target);
1816 }
1817}
1818
1819void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001820 LocationSummary* locations =
1821 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Alexandre Rames5319def2014-10-23 10:03:10 +01001822 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001823 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001824}
1825
1826void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001827 MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset());
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001828
1829 if (instruction->IsVolatile()) {
1830 if (kUseAcquireRelease) {
Calin Juravle77520bc2015-01-12 18:45:46 +00001831 // NB: LoadAcquire will record the pc info if needed.
1832 codegen_->LoadAcquire(instruction, OutputCPURegister(instruction), field);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001833 } else {
1834 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
Calin Juravle77520bc2015-01-12 18:45:46 +00001835 codegen_->MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001836 // For IRIW sequential consistency kLoadAny is not sufficient.
1837 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
1838 }
1839 } else {
1840 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
Calin Juravle77520bc2015-01-12 18:45:46 +00001841 codegen_->MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001842 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001843}
1844
1845void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001846 LocationSummary* locations =
1847 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Alexandre Rames5319def2014-10-23 10:03:10 +01001848 locations->SetInAt(0, Location::RequiresRegister());
1849 locations->SetInAt(1, Location::RequiresRegister());
1850}
1851
1852void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001853 Register obj = InputRegisterAt(instruction, 0);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001854 CPURegister value = InputCPURegisterAt(instruction, 1);
1855 Offset offset = instruction->GetFieldOffset();
1856 Primitive::Type field_type = instruction->GetFieldType();
1857
1858 if (instruction->IsVolatile()) {
1859 if (kUseAcquireRelease) {
1860 codegen_->StoreRelease(field_type, value, HeapOperand(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001861 codegen_->MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001862 } else {
1863 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
1864 codegen_->Store(field_type, value, HeapOperand(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001865 codegen_->MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001866 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
1867 }
1868 } else {
1869 codegen_->Store(field_type, value, HeapOperand(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001870 codegen_->MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001871 }
1872
1873 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001874 codegen_->MarkGCCard(obj, Register(value));
Alexandre Rames5319def2014-10-23 10:03:10 +01001875 }
1876}
1877
Alexandre Rames67555f72014-11-18 10:55:16 +00001878void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
1879 LocationSummary::CallKind call_kind =
1880 instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
1881 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
1882 locations->SetInAt(0, Location::RequiresRegister());
1883 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001884 // The output does overlap inputs.
1885 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Alexandre Rames67555f72014-11-18 10:55:16 +00001886}
1887
1888void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
1889 LocationSummary* locations = instruction->GetLocations();
1890 Register obj = InputRegisterAt(instruction, 0);;
1891 Register cls = InputRegisterAt(instruction, 1);;
1892 Register out = OutputRegister(instruction);
1893
1894 vixl::Label done;
1895
1896 // Return 0 if `obj` is null.
1897 // TODO: Avoid this check if we know `obj` is not null.
1898 __ Mov(out, 0);
1899 __ Cbz(obj, &done);
1900
1901 // Compare the class of `obj` with `cls`.
Serban Constantinescu02164b32014-11-13 14:05:07 +00001902 __ Ldr(out, HeapOperand(obj, mirror::Object::ClassOffset()));
Alexandre Rames67555f72014-11-18 10:55:16 +00001903 __ Cmp(out, cls);
1904 if (instruction->IsClassFinal()) {
1905 // Classes must be equal for the instanceof to succeed.
1906 __ Cset(out, eq);
1907 } else {
1908 // If the classes are not equal, we go into a slow path.
1909 DCHECK(locations->OnlyCallsOnSlowPath());
1910 SlowPathCodeARM64* slow_path =
Alexandre Rames3e69f162014-12-10 10:36:50 +00001911 new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(
1912 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Alexandre Rames67555f72014-11-18 10:55:16 +00001913 codegen_->AddSlowPath(slow_path);
1914 __ B(ne, slow_path->GetEntryLabel());
1915 __ Mov(out, 1);
1916 __ Bind(slow_path->GetExitLabel());
1917 }
1918
1919 __ Bind(&done);
1920}
1921
Alexandre Rames5319def2014-10-23 10:03:10 +01001922void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
1923 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1924 locations->SetOut(Location::ConstantLocation(constant));
1925}
1926
1927void InstructionCodeGeneratorARM64::VisitIntConstant(HIntConstant* constant) {
1928 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001929 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001930}
1931
Alexandre Rames5319def2014-10-23 10:03:10 +01001932void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
1933 LocationSummary* locations =
1934 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
1935 locations->AddTemp(LocationFrom(x0));
1936
1937 InvokeDexCallingConventionVisitor calling_convention_visitor;
1938 for (size_t i = 0; i < invoke->InputCount(); i++) {
1939 HInstruction* input = invoke->InputAt(i);
1940 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1941 }
1942
1943 Primitive::Type return_type = invoke->GetType();
1944 if (return_type != Primitive::kPrimVoid) {
1945 locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type));
1946 }
1947}
1948
Alexandre Rames67555f72014-11-18 10:55:16 +00001949void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1950 HandleInvoke(invoke);
1951}
1952
1953void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1954 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1955 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1956 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1957 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1958 Location receiver = invoke->GetLocations()->InAt(0);
1959 Offset class_offset = mirror::Object::ClassOffset();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001960 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
Alexandre Rames67555f72014-11-18 10:55:16 +00001961
1962 // The register ip1 is required to be used for the hidden argument in
1963 // art_quick_imt_conflict_trampoline, so prevent VIXL from using it.
1964 UseScratchRegisterScope scratch_scope(GetVIXLAssembler());
1965 scratch_scope.Exclude(ip1);
1966 __ Mov(ip1, invoke->GetDexMethodIndex());
1967
1968 // temp = object->GetClass();
1969 if (receiver.IsStackSlot()) {
1970 __ Ldr(temp, StackOperandFrom(receiver));
1971 __ Ldr(temp, HeapOperand(temp, class_offset));
1972 } else {
1973 __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
1974 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001975 codegen_->MaybeRecordImplicitNullCheck(invoke);
Alexandre Rames67555f72014-11-18 10:55:16 +00001976 // temp = temp->GetImtEntryAt(method_offset);
1977 __ Ldr(temp, HeapOperand(temp, method_offset));
1978 // lr = temp->GetEntryPoint();
1979 __ Ldr(lr, HeapOperand(temp, entry_point));
1980 // lr();
1981 __ Blr(lr);
1982 DCHECK(!codegen_->IsLeafMethod());
1983 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1984}
1985
1986void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1987 HandleInvoke(invoke);
1988}
1989
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001990void LocationsBuilderARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001991 HandleInvoke(invoke);
1992}
1993
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001994void InstructionCodeGeneratorARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001995 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1996 // Make sure that ArtMethod* is passed in W0 as per the calling convention
1997 DCHECK(temp.Is(w0));
1998 size_t index_in_cache = mirror::Array::DataOffset(kHeapRefSize).SizeValue() +
Andreas Gampe71fb52f2014-12-29 17:43:08 -08001999 invoke->GetDexMethodIndex() * kHeapRefSize;
Alexandre Rames5319def2014-10-23 10:03:10 +01002000
2001 // TODO: Implement all kinds of calls:
2002 // 1) boot -> boot
2003 // 2) app -> boot
2004 // 3) app -> app
2005 //
2006 // Currently we implement the app -> app logic, which looks up in the resolve cache.
2007
2008 // temp = method;
Alexandre Rames67555f72014-11-18 10:55:16 +00002009 codegen_->LoadCurrentMethod(temp);
Nicolas Geoffray4e44c822014-12-17 12:25:12 +00002010 // temp = temp->dex_cache_resolved_methods_;
2011 __ Ldr(temp, HeapOperand(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset()));
2012 // temp = temp[index_in_cache];
2013 __ Ldr(temp, HeapOperand(temp, index_in_cache));
Alexandre Rames5319def2014-10-23 10:03:10 +01002014 // lr = temp->entry_point_from_quick_compiled_code_;
Serban Constantinescu02164b32014-11-13 14:05:07 +00002015 __ Ldr(lr, HeapOperand(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
2016 kArm64WordSize)));
Alexandre Rames5319def2014-10-23 10:03:10 +01002017 // lr();
2018 __ Blr(lr);
2019
2020 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2021 DCHECK(!codegen_->IsLeafMethod());
2022}
2023
2024void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
2025 LocationSummary* locations = invoke->GetLocations();
2026 Location receiver = locations->InAt(0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00002027 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
Alexandre Rames5319def2014-10-23 10:03:10 +01002028 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
2029 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
2030 Offset class_offset = mirror::Object::ClassOffset();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00002031 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
Alexandre Rames5319def2014-10-23 10:03:10 +01002032
2033 // temp = object->GetClass();
2034 if (receiver.IsStackSlot()) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002035 __ Ldr(temp, MemOperand(sp, receiver.GetStackIndex()));
2036 __ Ldr(temp, HeapOperand(temp, class_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01002037 } else {
2038 DCHECK(receiver.IsRegister());
Serban Constantinescu02164b32014-11-13 14:05:07 +00002039 __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01002040 }
Calin Juravle77520bc2015-01-12 18:45:46 +00002041 codegen_->MaybeRecordImplicitNullCheck(invoke);
Alexandre Rames5319def2014-10-23 10:03:10 +01002042 // temp = temp->GetMethodAt(method_offset);
Serban Constantinescu02164b32014-11-13 14:05:07 +00002043 __ Ldr(temp, HeapOperand(temp, method_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01002044 // lr = temp->GetEntryPoint();
Serban Constantinescu02164b32014-11-13 14:05:07 +00002045 __ Ldr(lr, HeapOperand(temp, entry_point.SizeValue()));
Alexandre Rames5319def2014-10-23 10:03:10 +01002046 // lr();
2047 __ Blr(lr);
2048 DCHECK(!codegen_->IsLeafMethod());
2049 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2050}
2051
Alexandre Rames67555f72014-11-18 10:55:16 +00002052void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
2053 LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
2054 : LocationSummary::kNoCall;
2055 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
2056 locations->SetOut(Location::RequiresRegister());
2057}
2058
2059void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
2060 Register out = OutputRegister(cls);
2061 if (cls->IsReferrersClass()) {
2062 DCHECK(!cls->CanCallRuntime());
2063 DCHECK(!cls->MustGenerateClinitCheck());
2064 codegen_->LoadCurrentMethod(out);
2065 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
2066 } else {
2067 DCHECK(cls->CanCallRuntime());
2068 codegen_->LoadCurrentMethod(out);
2069 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset()));
Serban Constantinescu02164b32014-11-13 14:05:07 +00002070 __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Alexandre Rames67555f72014-11-18 10:55:16 +00002071
2072 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
2073 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
2074 codegen_->AddSlowPath(slow_path);
2075 __ Cbz(out, slow_path->GetEntryLabel());
2076 if (cls->MustGenerateClinitCheck()) {
2077 GenerateClassInitializationCheck(slow_path, out);
2078 } else {
2079 __ Bind(slow_path->GetExitLabel());
2080 }
2081 }
2082}
2083
2084void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
2085 LocationSummary* locations =
2086 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
2087 locations->SetOut(Location::RequiresRegister());
2088}
2089
2090void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
2091 MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
2092 __ Ldr(OutputRegister(instruction), exception);
2093 __ Str(wzr, exception);
2094}
2095
Alexandre Rames5319def2014-10-23 10:03:10 +01002096void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
2097 load->SetLocations(nullptr);
2098}
2099
2100void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) {
2101 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002102 UNUSED(load);
Alexandre Rames5319def2014-10-23 10:03:10 +01002103}
2104
Alexandre Rames67555f72014-11-18 10:55:16 +00002105void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
2106 LocationSummary* locations =
2107 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
2108 locations->SetOut(Location::RequiresRegister());
2109}
2110
2111void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
2112 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
2113 codegen_->AddSlowPath(slow_path);
2114
2115 Register out = OutputRegister(load);
2116 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08002117 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
2118 __ Ldr(out, HeapOperand(out, mirror::Class::DexCacheStringsOffset()));
Serban Constantinescu02164b32014-11-13 14:05:07 +00002119 __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Alexandre Rames67555f72014-11-18 10:55:16 +00002120 __ Cbz(out, slow_path->GetEntryLabel());
2121 __ Bind(slow_path->GetExitLabel());
2122}
2123
Alexandre Rames5319def2014-10-23 10:03:10 +01002124void LocationsBuilderARM64::VisitLocal(HLocal* local) {
2125 local->SetLocations(nullptr);
2126}
2127
2128void InstructionCodeGeneratorARM64::VisitLocal(HLocal* local) {
2129 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
2130}
2131
2132void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
2133 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
2134 locations->SetOut(Location::ConstantLocation(constant));
2135}
2136
2137void InstructionCodeGeneratorARM64::VisitLongConstant(HLongConstant* constant) {
2138 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002139 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01002140}
2141
Alexandre Rames67555f72014-11-18 10:55:16 +00002142void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
2143 LocationSummary* locations =
2144 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2145 InvokeRuntimeCallingConvention calling_convention;
2146 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2147}
2148
2149void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
2150 codegen_->InvokeRuntime(instruction->IsEnter()
2151 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
2152 instruction,
2153 instruction->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002154 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
Alexandre Rames67555f72014-11-18 10:55:16 +00002155}
2156
Alexandre Rames42d641b2014-10-27 14:00:51 +00002157void LocationsBuilderARM64::VisitMul(HMul* mul) {
2158 LocationSummary* locations =
2159 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2160 switch (mul->GetResultType()) {
2161 case Primitive::kPrimInt:
2162 case Primitive::kPrimLong:
2163 locations->SetInAt(0, Location::RequiresRegister());
2164 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00002165 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00002166 break;
2167
2168 case Primitive::kPrimFloat:
2169 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002170 locations->SetInAt(0, Location::RequiresFpuRegister());
2171 locations->SetInAt(1, Location::RequiresFpuRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00002172 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00002173 break;
2174
2175 default:
2176 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2177 }
2178}
2179
2180void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) {
2181 switch (mul->GetResultType()) {
2182 case Primitive::kPrimInt:
2183 case Primitive::kPrimLong:
2184 __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
2185 break;
2186
2187 case Primitive::kPrimFloat:
2188 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002189 __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1));
Alexandre Rames42d641b2014-10-27 14:00:51 +00002190 break;
2191
2192 default:
2193 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2194 }
2195}
2196
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002197void LocationsBuilderARM64::VisitNeg(HNeg* neg) {
2198 LocationSummary* locations =
2199 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2200 switch (neg->GetResultType()) {
2201 case Primitive::kPrimInt:
Alexandre Rames67555f72014-11-18 10:55:16 +00002202 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002203 locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0)));
Alexandre Rames67555f72014-11-18 10:55:16 +00002204 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002205 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002206
2207 case Primitive::kPrimFloat:
2208 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +00002209 locations->SetInAt(0, Location::RequiresFpuRegister());
2210 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002211 break;
2212
2213 default:
2214 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2215 }
2216}
2217
2218void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
2219 switch (neg->GetResultType()) {
2220 case Primitive::kPrimInt:
2221 case Primitive::kPrimLong:
2222 __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
2223 break;
2224
2225 case Primitive::kPrimFloat:
2226 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +00002227 __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002228 break;
2229
2230 default:
2231 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2232 }
2233}
2234
2235void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) {
2236 LocationSummary* locations =
2237 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2238 InvokeRuntimeCallingConvention calling_convention;
2239 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002240 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(2)));
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002241 locations->SetOut(LocationFrom(x0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002242 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(1)));
2243 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
2244 void*, uint32_t, int32_t, mirror::ArtMethod*>();
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002245}
2246
2247void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
2248 LocationSummary* locations = instruction->GetLocations();
2249 InvokeRuntimeCallingConvention calling_convention;
2250 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
2251 DCHECK(type_index.Is(w0));
2252 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002253 DCHECK(current_method.Is(w2));
Alexandre Rames67555f72014-11-18 10:55:16 +00002254 codegen_->LoadCurrentMethod(current_method);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002255 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +00002256 codegen_->InvokeRuntime(
2257 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002258 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
2259 void*, uint32_t, int32_t, mirror::ArtMethod*>();
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002260}
2261
Alexandre Rames5319def2014-10-23 10:03:10 +01002262void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
2263 LocationSummary* locations =
2264 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2265 InvokeRuntimeCallingConvention calling_convention;
2266 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
2267 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
2268 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002269 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, mirror::ArtMethod*>();
Alexandre Rames5319def2014-10-23 10:03:10 +01002270}
2271
2272void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) {
2273 LocationSummary* locations = instruction->GetLocations();
2274 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
2275 DCHECK(type_index.Is(w0));
2276 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
2277 DCHECK(current_method.Is(w1));
Alexandre Rames67555f72014-11-18 10:55:16 +00002278 codegen_->LoadCurrentMethod(current_method);
Alexandre Rames5319def2014-10-23 10:03:10 +01002279 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +00002280 codegen_->InvokeRuntime(
2281 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002282 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, mirror::ArtMethod*>();
Alexandre Rames5319def2014-10-23 10:03:10 +01002283}
2284
2285void LocationsBuilderARM64::VisitNot(HNot* instruction) {
2286 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Alexandre Rames4e596512014-11-07 15:56:50 +00002287 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00002288 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01002289}
2290
2291void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
2292 switch (instruction->InputAt(0)->GetType()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01002293 case Primitive::kPrimInt:
Alexandre Rames5319def2014-10-23 10:03:10 +01002294 case Primitive::kPrimLong:
Roland Levillain55dcfb52014-10-24 18:09:09 +01002295 __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
Alexandre Rames5319def2014-10-23 10:03:10 +01002296 break;
2297
2298 default:
2299 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
2300 }
2301}
2302
2303void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
2304 LocationSummary* locations =
2305 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2306 locations->SetInAt(0, Location::RequiresRegister());
2307 if (instruction->HasUses()) {
2308 locations->SetOut(Location::SameAsFirstInput());
2309 }
2310}
2311
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002312void InstructionCodeGeneratorARM64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002313 if (codegen_->CanMoveNullCheckToUser(instruction)) {
2314 return;
2315 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002316 Location obj = instruction->GetLocations()->InAt(0);
2317
2318 __ Ldr(wzr, HeapOperandFrom(obj, Offset(0)));
2319 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2320}
2321
2322void InstructionCodeGeneratorARM64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Alexandre Rames5319def2014-10-23 10:03:10 +01002323 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction);
2324 codegen_->AddSlowPath(slow_path);
2325
2326 LocationSummary* locations = instruction->GetLocations();
2327 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00002328
2329 __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel());
Alexandre Rames5319def2014-10-23 10:03:10 +01002330}
2331
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002332void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
2333 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
2334 GenerateImplicitNullCheck(instruction);
2335 } else {
2336 GenerateExplicitNullCheck(instruction);
2337 }
2338}
2339
Alexandre Rames67555f72014-11-18 10:55:16 +00002340void LocationsBuilderARM64::VisitOr(HOr* instruction) {
2341 HandleBinaryOp(instruction);
2342}
2343
2344void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) {
2345 HandleBinaryOp(instruction);
2346}
2347
Alexandre Rames3e69f162014-12-10 10:36:50 +00002348void LocationsBuilderARM64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
2349 LOG(FATAL) << "Unreachable";
2350}
2351
2352void InstructionCodeGeneratorARM64::VisitParallelMove(HParallelMove* instruction) {
2353 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
2354}
2355
Alexandre Rames5319def2014-10-23 10:03:10 +01002356void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
2357 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2358 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2359 if (location.IsStackSlot()) {
2360 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2361 } else if (location.IsDoubleStackSlot()) {
2362 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2363 }
2364 locations->SetOut(location);
2365}
2366
2367void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) {
2368 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002369 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002370}
2371
2372void LocationsBuilderARM64::VisitPhi(HPhi* instruction) {
2373 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2374 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2375 locations->SetInAt(i, Location::Any());
2376 }
2377 locations->SetOut(Location::Any());
2378}
2379
2380void InstructionCodeGeneratorARM64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002381 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002382 LOG(FATAL) << "Unreachable";
2383}
2384
Serban Constantinescu02164b32014-11-13 14:05:07 +00002385void LocationsBuilderARM64::VisitRem(HRem* rem) {
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002386 Primitive::Type type = rem->GetResultType();
2387 LocationSummary::CallKind call_kind = IsFPType(type) ? LocationSummary::kCall
2388 : LocationSummary::kNoCall;
2389 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2390
2391 switch (type) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002392 case Primitive::kPrimInt:
2393 case Primitive::kPrimLong:
2394 locations->SetInAt(0, Location::RequiresRegister());
2395 locations->SetInAt(1, Location::RequiresRegister());
2396 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2397 break;
2398
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002399 case Primitive::kPrimFloat:
2400 case Primitive::kPrimDouble: {
2401 InvokeRuntimeCallingConvention calling_convention;
2402 locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
2403 locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1)));
2404 locations->SetOut(calling_convention.GetReturnLocation(type));
2405
2406 break;
2407 }
2408
Serban Constantinescu02164b32014-11-13 14:05:07 +00002409 default:
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002410 LOG(FATAL) << "Unexpected rem type " << type;
Serban Constantinescu02164b32014-11-13 14:05:07 +00002411 }
2412}
2413
2414void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) {
2415 Primitive::Type type = rem->GetResultType();
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002416
Serban Constantinescu02164b32014-11-13 14:05:07 +00002417 switch (type) {
2418 case Primitive::kPrimInt:
2419 case Primitive::kPrimLong: {
2420 UseScratchRegisterScope temps(GetVIXLAssembler());
2421 Register dividend = InputRegisterAt(rem, 0);
2422 Register divisor = InputRegisterAt(rem, 1);
2423 Register output = OutputRegister(rem);
2424 Register temp = temps.AcquireSameSizeAs(output);
2425
2426 __ Sdiv(temp, dividend, divisor);
2427 __ Msub(output, temp, divisor, dividend);
2428 break;
2429 }
2430
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002431 case Primitive::kPrimFloat:
2432 case Primitive::kPrimDouble: {
2433 int32_t entry_offset = (type == Primitive::kPrimFloat) ? QUICK_ENTRY_POINT(pFmodf)
2434 : QUICK_ENTRY_POINT(pFmod);
2435 codegen_->InvokeRuntime(entry_offset, rem, rem->GetDexPc());
2436 break;
2437 }
2438
Serban Constantinescu02164b32014-11-13 14:05:07 +00002439 default:
2440 LOG(FATAL) << "Unexpected rem type " << type;
2441 }
2442}
2443
Alexandre Rames5319def2014-10-23 10:03:10 +01002444void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
2445 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2446 Primitive::Type return_type = instruction->InputAt(0)->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002447 locations->SetInAt(0, ARM64ReturnLocation(return_type));
Alexandre Rames5319def2014-10-23 10:03:10 +01002448}
2449
2450void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002451 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002452 codegen_->GenerateFrameExit();
Alexandre Rames3e69f162014-12-10 10:36:50 +00002453 __ Ret();
Alexandre Rames5319def2014-10-23 10:03:10 +01002454}
2455
2456void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) {
2457 instruction->SetLocations(nullptr);
2458}
2459
2460void InstructionCodeGeneratorARM64::VisitReturnVoid(HReturnVoid* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002461 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002462 codegen_->GenerateFrameExit();
Alexandre Rames3e69f162014-12-10 10:36:50 +00002463 __ Ret();
Alexandre Rames5319def2014-10-23 10:03:10 +01002464}
2465
Serban Constantinescu02164b32014-11-13 14:05:07 +00002466void LocationsBuilderARM64::VisitShl(HShl* shl) {
2467 HandleShift(shl);
2468}
2469
2470void InstructionCodeGeneratorARM64::VisitShl(HShl* shl) {
2471 HandleShift(shl);
2472}
2473
2474void LocationsBuilderARM64::VisitShr(HShr* shr) {
2475 HandleShift(shr);
2476}
2477
2478void InstructionCodeGeneratorARM64::VisitShr(HShr* shr) {
2479 HandleShift(shr);
2480}
2481
Alexandre Rames5319def2014-10-23 10:03:10 +01002482void LocationsBuilderARM64::VisitStoreLocal(HStoreLocal* store) {
2483 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
2484 Primitive::Type field_type = store->InputAt(1)->GetType();
2485 switch (field_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002486 case Primitive::kPrimNot:
Alexandre Rames5319def2014-10-23 10:03:10 +01002487 case Primitive::kPrimBoolean:
2488 case Primitive::kPrimByte:
2489 case Primitive::kPrimChar:
2490 case Primitive::kPrimShort:
2491 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002492 case Primitive::kPrimFloat:
Alexandre Rames5319def2014-10-23 10:03:10 +01002493 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
2494 break;
2495
2496 case Primitive::kPrimLong:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002497 case Primitive::kPrimDouble:
Alexandre Rames5319def2014-10-23 10:03:10 +01002498 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
2499 break;
2500
2501 default:
2502 LOG(FATAL) << "Unimplemented local type " << field_type;
2503 }
2504}
2505
2506void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002507 UNUSED(store);
Alexandre Rames5319def2014-10-23 10:03:10 +01002508}
2509
2510void LocationsBuilderARM64::VisitSub(HSub* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002511 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002512}
2513
2514void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002515 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002516}
2517
Alexandre Rames67555f72014-11-18 10:55:16 +00002518void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2519 LocationSummary* locations =
2520 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2521 locations->SetInAt(0, Location::RequiresRegister());
2522 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2523}
2524
2525void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002526 MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset());
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002527
2528 if (instruction->IsVolatile()) {
2529 if (kUseAcquireRelease) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002530 // NB: LoadAcquire will record the pc info if needed.
2531 codegen_->LoadAcquire(instruction, OutputCPURegister(instruction), field);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002532 } else {
2533 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
2534 // For IRIW sequential consistency kLoadAny is not sufficient.
2535 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2536 }
2537 } else {
2538 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
2539 }
Alexandre Rames67555f72014-11-18 10:55:16 +00002540}
2541
2542void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Alexandre Rames5319def2014-10-23 10:03:10 +01002543 LocationSummary* locations =
2544 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2545 locations->SetInAt(0, Location::RequiresRegister());
2546 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Rames5319def2014-10-23 10:03:10 +01002547}
2548
Alexandre Rames67555f72014-11-18 10:55:16 +00002549void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002550 Register cls = InputRegisterAt(instruction, 0);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002551 CPURegister value = InputCPURegisterAt(instruction, 1);
Serban Constantinescu02164b32014-11-13 14:05:07 +00002552 Offset offset = instruction->GetFieldOffset();
Alexandre Rames67555f72014-11-18 10:55:16 +00002553 Primitive::Type field_type = instruction->GetFieldType();
Alexandre Rames5319def2014-10-23 10:03:10 +01002554
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002555 if (instruction->IsVolatile()) {
2556 if (kUseAcquireRelease) {
2557 codegen_->StoreRelease(field_type, value, HeapOperand(cls, offset));
2558 } else {
2559 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2560 codegen_->Store(field_type, value, HeapOperand(cls, offset));
2561 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2562 }
2563 } else {
2564 codegen_->Store(field_type, value, HeapOperand(cls, offset));
2565 }
2566
2567 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002568 codegen_->MarkGCCard(cls, Register(value));
2569 }
Alexandre Rames5319def2014-10-23 10:03:10 +01002570}
2571
2572void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
2573 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
2574}
2575
2576void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002577 HBasicBlock* block = instruction->GetBlock();
2578 if (block->GetLoopInformation() != nullptr) {
2579 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
2580 // The back edge will generate the suspend check.
2581 return;
2582 }
2583 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
2584 // The goto will generate the suspend check.
2585 return;
2586 }
2587 GenerateSuspendCheck(instruction, nullptr);
Alexandre Rames5319def2014-10-23 10:03:10 +01002588}
2589
2590void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
2591 temp->SetLocations(nullptr);
2592}
2593
2594void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) {
2595 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002596 UNUSED(temp);
Alexandre Rames5319def2014-10-23 10:03:10 +01002597}
2598
Alexandre Rames67555f72014-11-18 10:55:16 +00002599void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
2600 LocationSummary* locations =
2601 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2602 InvokeRuntimeCallingConvention calling_convention;
2603 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2604}
2605
2606void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
2607 codegen_->InvokeRuntime(
2608 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002609 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Alexandre Rames67555f72014-11-18 10:55:16 +00002610}
2611
2612void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
2613 LocationSummary* locations =
2614 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
2615 Primitive::Type input_type = conversion->GetInputType();
2616 Primitive::Type result_type = conversion->GetResultType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002617 DCHECK_NE(input_type, result_type);
Alexandre Rames67555f72014-11-18 10:55:16 +00002618 if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
2619 (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
2620 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
2621 }
2622
2623 if (IsFPType(input_type)) {
2624 locations->SetInAt(0, Location::RequiresFpuRegister());
2625 } else {
2626 locations->SetInAt(0, Location::RequiresRegister());
2627 }
2628
2629 if (IsFPType(result_type)) {
2630 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2631 } else {
2632 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2633 }
2634}
2635
2636void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
2637 Primitive::Type result_type = conversion->GetResultType();
2638 Primitive::Type input_type = conversion->GetInputType();
2639
2640 DCHECK_NE(input_type, result_type);
2641
2642 if (IsIntegralType(result_type) && IsIntegralType(input_type)) {
2643 int result_size = Primitive::ComponentSize(result_type);
2644 int input_size = Primitive::ComponentSize(input_type);
Alexandre Rames3e69f162014-12-10 10:36:50 +00002645 int min_size = std::min(result_size, input_size);
Serban Constantinescu02164b32014-11-13 14:05:07 +00002646 Register output = OutputRegister(conversion);
2647 Register source = InputRegisterAt(conversion, 0);
Alexandre Rames3e69f162014-12-10 10:36:50 +00002648 if ((result_type == Primitive::kPrimChar) && (input_size < result_size)) {
2649 __ Ubfx(output, source, 0, result_size * kBitsPerByte);
2650 } else if ((result_type == Primitive::kPrimChar) ||
2651 ((input_type == Primitive::kPrimChar) && (result_size > input_size))) {
2652 __ Ubfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
Alexandre Rames67555f72014-11-18 10:55:16 +00002653 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +00002654 __ Sbfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
Alexandre Rames67555f72014-11-18 10:55:16 +00002655 }
Serban Constantinescu02164b32014-11-13 14:05:07 +00002656 } else if (IsFPType(result_type) && IsIntegralType(input_type)) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002657 __ Scvtf(OutputFPRegister(conversion), InputRegisterAt(conversion, 0));
2658 } else if (IsIntegralType(result_type) && IsFPType(input_type)) {
2659 CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
2660 __ Fcvtzs(OutputRegister(conversion), InputFPRegisterAt(conversion, 0));
2661 } else if (IsFPType(result_type) && IsFPType(input_type)) {
2662 __ Fcvt(OutputFPRegister(conversion), InputFPRegisterAt(conversion, 0));
2663 } else {
2664 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
2665 << " to " << result_type;
Alexandre Rames67555f72014-11-18 10:55:16 +00002666 }
Serban Constantinescu02164b32014-11-13 14:05:07 +00002667}
Alexandre Rames67555f72014-11-18 10:55:16 +00002668
Serban Constantinescu02164b32014-11-13 14:05:07 +00002669void LocationsBuilderARM64::VisitUShr(HUShr* ushr) {
2670 HandleShift(ushr);
2671}
2672
2673void InstructionCodeGeneratorARM64::VisitUShr(HUShr* ushr) {
2674 HandleShift(ushr);
Alexandre Rames67555f72014-11-18 10:55:16 +00002675}
2676
2677void LocationsBuilderARM64::VisitXor(HXor* instruction) {
2678 HandleBinaryOp(instruction);
2679}
2680
2681void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) {
2682 HandleBinaryOp(instruction);
2683}
2684
2685#undef __
2686#undef QUICK_ENTRY_POINT
2687
Alexandre Rames5319def2014-10-23 10:03:10 +01002688} // namespace arm64
2689} // namespace art