blob: 8d43a5dbb51abebfe62d317c86966f42c99d17f9 [file] [log] [blame]
Alexandre Rames5319def2014-10-23 10:03:10 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_arm64.h"
18
19#include "entrypoints/quick/quick_entrypoints.h"
20#include "gc/accounting/card_table.h"
21#include "mirror/array-inl.h"
22#include "mirror/art_method.h"
23#include "mirror/class.h"
24#include "thread.h"
25#include "utils/arm64/assembler_arm64.h"
26#include "utils/assembler.h"
27#include "utils/stack_checks.h"
28
29
30using namespace vixl; // NOLINT(build/namespaces)
31
32#ifdef __
33#error "ARM64 Codegen VIXL macro-assembler macro already defined."
34#endif
35
36
37namespace art {
38
39namespace arm64 {
40
Alexandre Rames5319def2014-10-23 10:03:10 +010041// TODO: clean-up some of the constant definitions.
42static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>);
43static constexpr int kCurrentMethodStackOffset = 0;
44
45namespace {
Alexandre Ramesa89086e2014-11-07 17:13:25 +000046
47bool IsFPType(Primitive::Type type) {
48 return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble;
49}
50
Alexandre Rames67555f72014-11-18 10:55:16 +000051bool IsIntegralType(Primitive::Type type) {
52 switch (type) {
53 case Primitive::kPrimByte:
54 case Primitive::kPrimChar:
55 case Primitive::kPrimShort:
56 case Primitive::kPrimInt:
57 case Primitive::kPrimLong:
58 return true;
59 default:
60 return false;
61 }
62}
63
Alexandre Ramesa89086e2014-11-07 17:13:25 +000064bool Is64BitType(Primitive::Type type) {
65 return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
66}
67
Alexandre Rames5319def2014-10-23 10:03:10 +010068// Convenience helpers to ease conversion to and from VIXL operands.
Alexandre Rames67555f72014-11-18 10:55:16 +000069static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32),
70 "Unexpected values for register codes.");
Alexandre Rames5319def2014-10-23 10:03:10 +010071
72int VIXLRegCodeFromART(int code) {
Alexandre Rames5319def2014-10-23 10:03:10 +010073 if (code == SP) {
74 return vixl::kSPRegInternalCode;
75 }
76 if (code == XZR) {
77 return vixl::kZeroRegCode;
78 }
79 return code;
80}
81
82int ARTRegCodeFromVIXL(int code) {
Alexandre Rames5319def2014-10-23 10:03:10 +010083 if (code == vixl::kSPRegInternalCode) {
84 return SP;
85 }
86 if (code == vixl::kZeroRegCode) {
87 return XZR;
88 }
89 return code;
90}
91
92Register XRegisterFrom(Location location) {
93 return Register::XRegFromCode(VIXLRegCodeFromART(location.reg()));
94}
95
96Register WRegisterFrom(Location location) {
97 return Register::WRegFromCode(VIXLRegCodeFromART(location.reg()));
98}
99
100Register RegisterFrom(Location location, Primitive::Type type) {
101 DCHECK(type != Primitive::kPrimVoid && !IsFPType(type));
102 return type == Primitive::kPrimLong ? XRegisterFrom(location) : WRegisterFrom(location);
103}
104
105Register OutputRegister(HInstruction* instr) {
106 return RegisterFrom(instr->GetLocations()->Out(), instr->GetType());
107}
108
109Register InputRegisterAt(HInstruction* instr, int input_index) {
110 return RegisterFrom(instr->GetLocations()->InAt(input_index),
111 instr->InputAt(input_index)->GetType());
112}
113
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000114FPRegister DRegisterFrom(Location location) {
115 return FPRegister::DRegFromCode(location.reg());
116}
117
118FPRegister SRegisterFrom(Location location) {
119 return FPRegister::SRegFromCode(location.reg());
120}
121
122FPRegister FPRegisterFrom(Location location, Primitive::Type type) {
123 DCHECK(IsFPType(type));
124 return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location);
125}
126
127FPRegister OutputFPRegister(HInstruction* instr) {
128 return FPRegisterFrom(instr->GetLocations()->Out(), instr->GetType());
129}
130
131FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) {
132 return FPRegisterFrom(instr->GetLocations()->InAt(input_index),
133 instr->InputAt(input_index)->GetType());
134}
135
Alexandre Rames67555f72014-11-18 10:55:16 +0000136CPURegister OutputCPURegister(HInstruction* instr) {
137 return IsFPType(instr->GetType()) ? static_cast<CPURegister>(OutputFPRegister(instr))
138 : static_cast<CPURegister>(OutputRegister(instr));
139}
140
141CPURegister InputCPURegisterAt(HInstruction* instr, int index) {
142 return IsFPType(instr->InputAt(index)->GetType())
143 ? static_cast<CPURegister>(InputFPRegisterAt(instr, index))
144 : static_cast<CPURegister>(InputRegisterAt(instr, index));
145}
146
Alexandre Rames5319def2014-10-23 10:03:10 +0100147int64_t Int64ConstantFrom(Location location) {
148 HConstant* instr = location.GetConstant();
149 return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue()
150 : instr->AsLongConstant()->GetValue();
151}
152
153Operand OperandFrom(Location location, Primitive::Type type) {
154 if (location.IsRegister()) {
155 return Operand(RegisterFrom(location, type));
156 } else {
157 return Operand(Int64ConstantFrom(location));
158 }
159}
160
161Operand InputOperandAt(HInstruction* instr, int input_index) {
162 return OperandFrom(instr->GetLocations()->InAt(input_index),
163 instr->InputAt(input_index)->GetType());
164}
165
166MemOperand StackOperandFrom(Location location) {
167 return MemOperand(sp, location.GetStackIndex());
168}
169
Alexandre Rames67555f72014-11-18 10:55:16 +0000170MemOperand HeapOperand(const Register& base, size_t offset) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100171 // A heap reference must be 32bit, so fit in a W register.
172 DCHECK(base.IsW());
Alexandre Rames67555f72014-11-18 10:55:16 +0000173 return MemOperand(base.X(), offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100174}
175
Alexandre Rames67555f72014-11-18 10:55:16 +0000176MemOperand HeapOperand(const Register& base, Offset offset) {
177 return HeapOperand(base, offset.SizeValue());
178}
179
180MemOperand HeapOperandFrom(Location location, Offset offset) {
181 return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100182}
183
184Location LocationFrom(const Register& reg) {
185 return Location::RegisterLocation(ARTRegCodeFromVIXL(reg.code()));
186}
187
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000188Location LocationFrom(const FPRegister& fpreg) {
189 return Location::FpuRegisterLocation(fpreg.code());
190}
191
Alexandre Rames5319def2014-10-23 10:03:10 +0100192} // namespace
193
194inline Condition ARM64Condition(IfCondition cond) {
195 switch (cond) {
196 case kCondEQ: return eq;
197 case kCondNE: return ne;
198 case kCondLT: return lt;
199 case kCondLE: return le;
200 case kCondGT: return gt;
201 case kCondGE: return ge;
202 default:
203 LOG(FATAL) << "Unknown if condition";
204 }
205 return nv; // Unreachable.
206}
207
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000208Location ARM64ReturnLocation(Primitive::Type return_type) {
209 DCHECK_NE(return_type, Primitive::kPrimVoid);
210 // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the
211 // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`,
212 // but we use the exact registers for clarity.
213 if (return_type == Primitive::kPrimFloat) {
214 return LocationFrom(s0);
215 } else if (return_type == Primitive::kPrimDouble) {
216 return LocationFrom(d0);
217 } else if (return_type == Primitive::kPrimLong) {
218 return LocationFrom(x0);
219 } else {
220 return LocationFrom(w0);
221 }
222}
223
Alexandre Rames5319def2014-10-23 10:03:10 +0100224static const Register kRuntimeParameterCoreRegisters[] = { x0, x1, x2, x3, x4, x5, x6, x7 };
225static constexpr size_t kRuntimeParameterCoreRegistersLength =
226 arraysize(kRuntimeParameterCoreRegisters);
227static const FPRegister kRuntimeParameterFpuRegisters[] = { };
228static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
229
230class InvokeRuntimeCallingConvention : public CallingConvention<Register, FPRegister> {
231 public:
232 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
233
234 InvokeRuntimeCallingConvention()
235 : CallingConvention(kRuntimeParameterCoreRegisters,
236 kRuntimeParameterCoreRegistersLength,
237 kRuntimeParameterFpuRegisters,
238 kRuntimeParameterFpuRegistersLength) {}
239
240 Location GetReturnLocation(Primitive::Type return_type);
241
242 private:
243 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
244};
245
246Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type return_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000247 return ARM64ReturnLocation(return_type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100248}
249
Alexandre Rames67555f72014-11-18 10:55:16 +0000250#define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
251#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
Alexandre Rames5319def2014-10-23 10:03:10 +0100252
253class SlowPathCodeARM64 : public SlowPathCode {
254 public:
255 SlowPathCodeARM64() : entry_label_(), exit_label_() {}
256
257 vixl::Label* GetEntryLabel() { return &entry_label_; }
258 vixl::Label* GetExitLabel() { return &exit_label_; }
259
260 private:
261 vixl::Label entry_label_;
262 vixl::Label exit_label_;
263
264 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM64);
265};
266
267class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
268 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000269 BoundsCheckSlowPathARM64() {}
Alexandre Rames5319def2014-10-23 10:03:10 +0100270
Alexandre Rames67555f72014-11-18 10:55:16 +0000271 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames5319def2014-10-23 10:03:10 +0100272 __ Bind(GetEntryLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000273 __ Brk(__LINE__); // TODO: Unimplemented BoundsCheckSlowPathARM64.
Alexandre Rames5319def2014-10-23 10:03:10 +0100274 }
275
276 private:
Alexandre Rames5319def2014-10-23 10:03:10 +0100277 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
278};
279
Alexandre Rames67555f72014-11-18 10:55:16 +0000280class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 {
281 public:
282 explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : instruction_(instruction) {}
283
284 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
285 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
286 __ Bind(GetEntryLabel());
287 arm64_codegen->InvokeRuntime(
288 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
289 }
290
291 private:
292 HDivZeroCheck* const instruction_;
293 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64);
294};
295
296class LoadClassSlowPathARM64 : public SlowPathCodeARM64 {
297 public:
298 LoadClassSlowPathARM64(HLoadClass* cls,
299 HInstruction* at,
300 uint32_t dex_pc,
301 bool do_clinit)
302 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
303 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
304 }
305
306 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
307 LocationSummary* locations = at_->GetLocations();
308 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
309
310 __ Bind(GetEntryLabel());
311 codegen->SaveLiveRegisters(locations);
312
313 InvokeRuntimeCallingConvention calling_convention;
314 __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
315 arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W());
316 int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
317 : QUICK_ENTRY_POINT(pInitializeType);
318 arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
319
320 // Move the class to the desired location.
321 Location out = locations->Out();
322 if (out.IsValid()) {
323 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
324 Primitive::Type type = at_->GetType();
325 arm64_codegen->MoveHelper(out, calling_convention.GetReturnLocation(type), type);
326 }
327
328 codegen->RestoreLiveRegisters(locations);
329 __ B(GetExitLabel());
330 }
331
332 private:
333 // The class this slow path will load.
334 HLoadClass* const cls_;
335
336 // The instruction where this slow path is happening.
337 // (Might be the load class or an initialization check).
338 HInstruction* const at_;
339
340 // The dex PC of `at_`.
341 const uint32_t dex_pc_;
342
343 // Whether to initialize the class.
344 const bool do_clinit_;
345
346 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
347};
348
349class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
350 public:
351 explicit LoadStringSlowPathARM64(HLoadString* instruction) : instruction_(instruction) {}
352
353 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
354 LocationSummary* locations = instruction_->GetLocations();
355 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
356 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
357
358 __ Bind(GetEntryLabel());
359 codegen->SaveLiveRegisters(locations);
360
361 InvokeRuntimeCallingConvention calling_convention;
362 arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0).W());
363 __ Mov(calling_convention.GetRegisterAt(1).W(), instruction_->GetStringIndex());
364 arm64_codegen->InvokeRuntime(
365 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
366 Primitive::Type type = instruction_->GetType();
367 arm64_codegen->MoveHelper(locations->Out(), calling_convention.GetReturnLocation(type), type);
368
369 codegen->RestoreLiveRegisters(locations);
370 __ B(GetExitLabel());
371 }
372
373 private:
374 HLoadString* const instruction_;
375
376 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
377};
378
Alexandre Rames5319def2014-10-23 10:03:10 +0100379class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
380 public:
381 explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {}
382
Alexandre Rames67555f72014-11-18 10:55:16 +0000383 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
384 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100385 __ Bind(GetEntryLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000386 arm64_codegen->InvokeRuntime(
387 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
Alexandre Rames5319def2014-10-23 10:03:10 +0100388 }
389
390 private:
391 HNullCheck* const instruction_;
392
393 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM64);
394};
395
396class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 {
397 public:
398 explicit SuspendCheckSlowPathARM64(HSuspendCheck* instruction,
399 HBasicBlock* successor)
400 : instruction_(instruction), successor_(successor) {}
401
Alexandre Rames67555f72014-11-18 10:55:16 +0000402 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
403 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100404 __ Bind(GetEntryLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000405 codegen->SaveLiveRegisters(instruction_->GetLocations());
406 arm64_codegen->InvokeRuntime(
407 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
408 codegen->RestoreLiveRegisters(instruction_->GetLocations());
409 if (successor_ == nullptr) {
410 __ B(GetReturnLabel());
411 } else {
412 __ B(arm64_codegen->GetLabelOf(successor_));
413 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100414 }
415
416 vixl::Label* GetReturnLabel() {
417 DCHECK(successor_ == nullptr);
418 return &return_label_;
419 }
420
421
422 private:
423 HSuspendCheck* const instruction_;
424 // If not null, the block to branch to after the suspend check.
425 HBasicBlock* const successor_;
426
427 // If `successor_` is null, the label to branch to after the suspend check.
428 vixl::Label return_label_;
429
430 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
431};
432
Alexandre Rames67555f72014-11-18 10:55:16 +0000433class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
434 public:
435 TypeCheckSlowPathARM64() {}
436
437 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
438 __ Bind(GetEntryLabel());
439 __ Brk(__LINE__); // TODO: Unimplemented TypeCheckSlowPathARM64.
440 __ b(GetExitLabel());
441 }
442
443 private:
444 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64);
445};
446
Alexandre Rames5319def2014-10-23 10:03:10 +0100447#undef __
448
449Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
450 Location next_location;
451 if (type == Primitive::kPrimVoid) {
452 LOG(FATAL) << "Unreachable type " << type;
453 }
454
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000455 if (IsFPType(type) && (fp_index_ < calling_convention.GetNumberOfFpuRegisters())) {
456 next_location = LocationFrom(calling_convention.GetFpuRegisterAt(fp_index_++));
457 } else if (!IsFPType(type) && (gp_index_ < calling_convention.GetNumberOfRegisters())) {
458 next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++));
459 } else {
460 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
461 next_location = Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
462 : Location::StackSlot(stack_offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100463 }
464
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000465 // Space on the stack is reserved for all arguments.
466 stack_index_ += Is64BitType(type) ? 2 : 1;
Alexandre Rames5319def2014-10-23 10:03:10 +0100467 return next_location;
468}
469
470CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph)
471 : CodeGenerator(graph,
472 kNumberOfAllocatableRegisters,
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000473 kNumberOfAllocatableFPRegisters,
Alexandre Rames5319def2014-10-23 10:03:10 +0100474 kNumberOfAllocatableRegisterPairs),
475 block_labels_(nullptr),
476 location_builder_(graph, this),
477 instruction_visitor_(graph, this) {}
478
Alexandre Rames67555f72014-11-18 10:55:16 +0000479#undef __
480#define __ GetVIXLAssembler()->
Alexandre Rames5319def2014-10-23 10:03:10 +0100481
Serban Constantinescu32f5b4d2014-11-25 20:05:46 +0000482void CodeGeneratorARM64::Finalize(CodeAllocator* allocator) {
483 // Ensure we emit the literal pool.
484 __ FinalizeCode();
485 CodeGenerator::Finalize(allocator);
486}
487
Alexandre Rames5319def2014-10-23 10:03:10 +0100488void CodeGeneratorARM64::GenerateFrameEntry() {
489 // TODO: Add proper support for the stack overflow check.
Alexandre Rames67555f72014-11-18 10:55:16 +0000490 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100491 Register temp = temps.AcquireX();
492 __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
493 __ Ldr(temp, MemOperand(temp, 0));
494 RecordPcInfo(nullptr, 0);
495
496 CPURegList preserved_regs = GetFramePreservedRegisters();
497 int frame_size = GetFrameSize();
498 core_spill_mask_ |= preserved_regs.list();
499
500 __ Str(w0, MemOperand(sp, -frame_size, PreIndex));
501 __ PokeCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
502
503 // Stack layout:
504 // sp[frame_size - 8] : lr.
505 // ... : other preserved registers.
506 // sp[frame_size - regs_size]: first preserved register.
507 // ... : reserved frame space.
Alexandre Rames67555f72014-11-18 10:55:16 +0000508 // sp[0] : current method.
Alexandre Rames5319def2014-10-23 10:03:10 +0100509}
510
511void CodeGeneratorARM64::GenerateFrameExit() {
512 int frame_size = GetFrameSize();
513 CPURegList preserved_regs = GetFramePreservedRegisters();
514 __ PeekCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
515 __ Drop(frame_size);
516}
517
518void CodeGeneratorARM64::Bind(HBasicBlock* block) {
519 __ Bind(GetLabelOf(block));
520}
521
Alexandre Rames5319def2014-10-23 10:03:10 +0100522void CodeGeneratorARM64::Move(HInstruction* instruction,
523 Location location,
524 HInstruction* move_for) {
525 LocationSummary* locations = instruction->GetLocations();
526 if (locations != nullptr && locations->Out().Equals(location)) {
527 return;
528 }
529
530 Primitive::Type type = instruction->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000531 DCHECK_NE(type, Primitive::kPrimVoid);
Alexandre Rames5319def2014-10-23 10:03:10 +0100532
533 if (instruction->IsIntConstant() || instruction->IsLongConstant()) {
534 int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue()
535 : instruction->AsLongConstant()->GetValue();
536 if (location.IsRegister()) {
537 Register dst = RegisterFrom(location, type);
538 DCHECK((instruction->IsIntConstant() && dst.Is32Bits()) ||
539 (instruction->IsLongConstant() && dst.Is64Bits()));
540 __ Mov(dst, value);
541 } else {
542 DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
Alexandre Rames67555f72014-11-18 10:55:16 +0000543 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100544 Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
545 __ Mov(temp, value);
546 __ Str(temp, StackOperandFrom(location));
547 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000548 } else if (instruction->IsTemporary()) {
549 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
550 MoveHelper(location, temp_location, type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100551 } else if (instruction->IsLoadLocal()) {
552 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000553 if (Is64BitType(type)) {
554 MoveHelper(location, Location::DoubleStackSlot(stack_slot), type);
555 } else {
556 MoveHelper(location, Location::StackSlot(stack_slot), type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100557 }
558
559 } else {
560 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
561 MoveHelper(location, locations->Out(), type);
562 }
563}
564
565size_t CodeGeneratorARM64::FrameEntrySpillSize() const {
566 return GetFramePreservedRegistersSize();
567}
568
569Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const {
570 Primitive::Type type = load->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000571
Alexandre Rames5319def2014-10-23 10:03:10 +0100572 switch (type) {
573 case Primitive::kPrimNot:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000574 case Primitive::kPrimInt:
575 case Primitive::kPrimFloat:
576 return Location::StackSlot(GetStackSlot(load->GetLocal()));
577
578 case Primitive::kPrimLong:
579 case Primitive::kPrimDouble:
580 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
581
Alexandre Rames5319def2014-10-23 10:03:10 +0100582 case Primitive::kPrimBoolean:
583 case Primitive::kPrimByte:
584 case Primitive::kPrimChar:
585 case Primitive::kPrimShort:
Alexandre Rames5319def2014-10-23 10:03:10 +0100586 case Primitive::kPrimVoid:
Alexandre Rames5319def2014-10-23 10:03:10 +0100587 LOG(FATAL) << "Unexpected type " << type;
588 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000589
Alexandre Rames5319def2014-10-23 10:03:10 +0100590 LOG(FATAL) << "Unreachable";
591 return Location::NoLocation();
592}
593
594void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
Alexandre Rames67555f72014-11-18 10:55:16 +0000595 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100596 Register card = temps.AcquireX();
597 Register temp = temps.AcquireX();
598 vixl::Label done;
599 __ Cbz(value, &done);
600 __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
601 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
602 __ Strb(card, MemOperand(card, temp));
603 __ Bind(&done);
604}
605
606void CodeGeneratorARM64::SetupBlockedRegisters() const {
607 // Block reserved registers:
608 // ip0 (VIXL temporary)
609 // ip1 (VIXL temporary)
610 // xSuspend (Suspend counter)
611 // lr
612 // sp is not part of the allocatable registers, so we don't need to block it.
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000613 // TODO: Avoid blocking callee-saved registers, and instead preserve them
614 // where necessary.
Alexandre Rames5319def2014-10-23 10:03:10 +0100615 CPURegList reserved_core_registers = vixl_reserved_core_registers;
616 reserved_core_registers.Combine(runtime_reserved_core_registers);
Alexandre Rames5319def2014-10-23 10:03:10 +0100617 reserved_core_registers.Combine(quick_callee_saved_registers);
618 while (!reserved_core_registers.IsEmpty()) {
619 blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true;
620 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000621 CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
622 reserved_fp_registers.Combine(CPURegList::GetCalleeSavedFP());
623 while (!reserved_core_registers.IsEmpty()) {
624 blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().code()] = true;
625 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100626}
627
628Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const {
629 if (type == Primitive::kPrimVoid) {
630 LOG(FATAL) << "Unreachable type " << type;
631 }
632
Alexandre Rames5319def2014-10-23 10:03:10 +0100633 if (IsFPType(type)) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000634 ssize_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfAllocatableFPRegisters);
635 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100636 return Location::FpuRegisterLocation(reg);
637 } else {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000638 ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfAllocatableRegisters);
639 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100640 return Location::RegisterLocation(reg);
641 }
642}
643
644void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
645 stream << Arm64ManagedRegister::FromXRegister(XRegister(reg));
646}
647
648void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
649 stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
650}
651
Alexandre Rames67555f72014-11-18 10:55:16 +0000652void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
653 if (constant->IsIntConstant() || constant->IsLongConstant()) {
654 __ Mov(Register(destination),
655 constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
656 : constant->AsLongConstant()->GetValue());
657 } else if (constant->IsFloatConstant()) {
658 __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
659 } else {
660 DCHECK(constant->IsDoubleConstant());
661 __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue());
662 }
663}
664
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000665void CodeGeneratorARM64::MoveHelper(Location destination,
666 Location source,
667 Primitive::Type type) {
668 if (source.Equals(destination)) {
669 return;
670 }
671 if (destination.IsRegister()) {
672 Register dst = RegisterFrom(destination, type);
673 if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
674 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
675 __ Ldr(dst, StackOperandFrom(source));
676 } else {
677 __ Mov(dst, OperandFrom(source, type));
678 }
679 } else if (destination.IsFpuRegister()) {
680 FPRegister dst = FPRegisterFrom(destination, type);
681 if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
682 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
683 __ Ldr(dst, StackOperandFrom(source));
684 } else if (source.IsFpuRegister()) {
685 __ Fmov(dst, FPRegisterFrom(source, type));
686 } else {
Alexandre Rames67555f72014-11-18 10:55:16 +0000687 MoveConstant(dst, source.GetConstant());
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000688 }
689 } else {
690 DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
691 if (source.IsRegister()) {
692 __ Str(RegisterFrom(source, type), StackOperandFrom(destination));
693 } else if (source.IsFpuRegister()) {
694 __ Str(FPRegisterFrom(source, type), StackOperandFrom(destination));
Alexandre Rames67555f72014-11-18 10:55:16 +0000695 } else if (source.IsConstant()) {
696 UseScratchRegisterScope temps(GetVIXLAssembler());
697 HConstant* cst = source.GetConstant();
698 CPURegister temp;
699 if (cst->IsIntConstant() || cst->IsLongConstant()) {
700 temp = cst->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
701 } else {
702 DCHECK(cst->IsFloatConstant() || cst->IsDoubleConstant());
703 temp = cst->IsFloatConstant() ? temps.AcquireS() : temps.AcquireD();
704 }
705 MoveConstant(temp, cst);
706 __ Str(temp, StackOperandFrom(destination));
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000707 } else {
Alexandre Rames67555f72014-11-18 10:55:16 +0000708 DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
709 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000710 Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW();
711 __ Ldr(temp, StackOperandFrom(source));
712 __ Str(temp, StackOperandFrom(destination));
713 }
714 }
715}
716
717void CodeGeneratorARM64::Load(Primitive::Type type,
Alexandre Rames67555f72014-11-18 10:55:16 +0000718 vixl::CPURegister dst,
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000719 const vixl::MemOperand& src) {
720 switch (type) {
721 case Primitive::kPrimBoolean:
Alexandre Rames67555f72014-11-18 10:55:16 +0000722 __ Ldrb(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000723 break;
724 case Primitive::kPrimByte:
Alexandre Rames67555f72014-11-18 10:55:16 +0000725 __ Ldrsb(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000726 break;
727 case Primitive::kPrimShort:
Alexandre Rames67555f72014-11-18 10:55:16 +0000728 __ Ldrsh(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000729 break;
730 case Primitive::kPrimChar:
Alexandre Rames67555f72014-11-18 10:55:16 +0000731 __ Ldrh(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000732 break;
733 case Primitive::kPrimInt:
734 case Primitive::kPrimNot:
735 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000736 case Primitive::kPrimFloat:
737 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +0000738 DCHECK(dst.Is64Bits() == Is64BitType(type));
739 __ Ldr(dst, src);
740 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000741 case Primitive::kPrimVoid:
742 LOG(FATAL) << "Unreachable type " << type;
743 }
744}
745
746void CodeGeneratorARM64::Store(Primitive::Type type,
Alexandre Rames67555f72014-11-18 10:55:16 +0000747 vixl::CPURegister rt,
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000748 const vixl::MemOperand& dst) {
749 switch (type) {
750 case Primitive::kPrimBoolean:
751 case Primitive::kPrimByte:
Alexandre Rames67555f72014-11-18 10:55:16 +0000752 __ Strb(Register(rt), dst);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000753 break;
754 case Primitive::kPrimChar:
755 case Primitive::kPrimShort:
Alexandre Rames67555f72014-11-18 10:55:16 +0000756 __ Strh(Register(rt), dst);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000757 break;
758 case Primitive::kPrimInt:
759 case Primitive::kPrimNot:
760 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000761 case Primitive::kPrimFloat:
762 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +0000763 DCHECK(rt.Is64Bits() == Is64BitType(type));
764 __ Str(rt, dst);
765 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000766 case Primitive::kPrimVoid:
767 LOG(FATAL) << "Unreachable type " << type;
768 }
769}
770
Alexandre Rames67555f72014-11-18 10:55:16 +0000771void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) {
772 DCHECK(current_method.IsW());
773 __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
774}
775
776void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
777 HInstruction* instruction,
778 uint32_t dex_pc) {
779 __ Ldr(lr, MemOperand(tr, entry_point_offset));
780 __ Blr(lr);
781 RecordPcInfo(instruction, dex_pc);
782 DCHECK(instruction->IsSuspendCheck()
783 || instruction->IsBoundsCheck()
784 || instruction->IsNullCheck()
785 || instruction->IsDivZeroCheck()
786 || !IsLeafMethod());
787}
788
789void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
790 vixl::Register class_reg) {
791 UseScratchRegisterScope temps(GetVIXLAssembler());
792 Register temp = temps.AcquireW();
793 __ Ldr(temp, HeapOperand(class_reg, mirror::Class::StatusOffset()));
794 __ Cmp(temp, mirror::Class::kStatusInitialized);
795 __ B(lt, slow_path->GetEntryLabel());
796 // Even if the initialized flag is set, we may be in a situation where caches are not synced
797 // properly. Therefore, we do a memory fence.
798 __ Dmb(InnerShareable, BarrierAll);
799 __ Bind(slow_path->GetExitLabel());
800}
Alexandre Rames5319def2014-10-23 10:03:10 +0100801
802InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
803 CodeGeneratorARM64* codegen)
804 : HGraphVisitor(graph),
805 assembler_(codegen->GetAssembler()),
806 codegen_(codegen) {}
807
808#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100809 M(ParallelMove) \
Calin Juravle9aec02f2014-11-18 23:06:35 +0000810 M(Rem) \
811 M(Shl) \
812 M(Shr) \
813 M(UShr) \
Alexandre Rames5319def2014-10-23 10:03:10 +0100814
815#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
816
817enum UnimplementedInstructionBreakCode {
Alexandre Rames67555f72014-11-18 10:55:16 +0000818 // Using a base helps identify when we hit such breakpoints.
819 UnimplementedInstructionBreakCodeBaseCode = 0x900,
Alexandre Rames5319def2014-10-23 10:03:10 +0100820#define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name),
821 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION)
822#undef ENUM_UNIMPLEMENTED_INSTRUCTION
823};
824
825#define DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS(name) \
826 void InstructionCodeGeneratorARM64::Visit##name(H##name* instr) { \
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700827 UNUSED(instr); \
Alexandre Rames5319def2014-10-23 10:03:10 +0100828 __ Brk(UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name)); \
829 } \
830 void LocationsBuilderARM64::Visit##name(H##name* instr) { \
831 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); \
832 locations->SetOut(Location::Any()); \
833 }
834 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS)
835#undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS
836
837#undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE
Alexandre Rames67555f72014-11-18 10:55:16 +0000838#undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION
Alexandre Rames5319def2014-10-23 10:03:10 +0100839
Alexandre Rames67555f72014-11-18 10:55:16 +0000840void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100841 DCHECK_EQ(instr->InputCount(), 2U);
842 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
843 Primitive::Type type = instr->GetResultType();
844 switch (type) {
845 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000846 case Primitive::kPrimLong:
Alexandre Rames5319def2014-10-23 10:03:10 +0100847 locations->SetInAt(0, Location::RequiresRegister());
848 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +0000849 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +0100850 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000851
852 case Primitive::kPrimFloat:
853 case Primitive::kPrimDouble:
854 locations->SetInAt(0, Location::RequiresFpuRegister());
855 locations->SetInAt(1, Location::RequiresFpuRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +0000856 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +0100857 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000858
Alexandre Rames5319def2014-10-23 10:03:10 +0100859 default:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000860 LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +0100861 }
862}
863
Alexandre Rames67555f72014-11-18 10:55:16 +0000864void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100865 Primitive::Type type = instr->GetType();
Alexandre Rames5319def2014-10-23 10:03:10 +0100866
867 switch (type) {
868 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000869 case Primitive::kPrimLong: {
870 Register dst = OutputRegister(instr);
871 Register lhs = InputRegisterAt(instr, 0);
872 Operand rhs = InputOperandAt(instr, 1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100873 if (instr->IsAdd()) {
874 __ Add(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +0000875 } else if (instr->IsAnd()) {
876 __ And(dst, lhs, rhs);
877 } else if (instr->IsOr()) {
878 __ Orr(dst, lhs, rhs);
879 } else if (instr->IsSub()) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100880 __ Sub(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +0000881 } else {
882 DCHECK(instr->IsXor());
883 __ Eor(dst, lhs, rhs);
Alexandre Rames5319def2014-10-23 10:03:10 +0100884 }
885 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000886 }
887 case Primitive::kPrimFloat:
888 case Primitive::kPrimDouble: {
889 FPRegister dst = OutputFPRegister(instr);
890 FPRegister lhs = InputFPRegisterAt(instr, 0);
891 FPRegister rhs = InputFPRegisterAt(instr, 1);
892 if (instr->IsAdd()) {
893 __ Fadd(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +0000894 } else if (instr->IsSub()) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000895 __ Fsub(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +0000896 } else {
897 LOG(FATAL) << "Unexpected floating-point binary operation";
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000898 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100899 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000900 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100901 default:
Alexandre Rames67555f72014-11-18 10:55:16 +0000902 LOG(FATAL) << "Unexpected binary operation type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +0100903 }
904}
905
906void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +0000907 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +0100908}
909
910void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +0000911 HandleBinaryOp(instruction);
912}
913
914void LocationsBuilderARM64::VisitAnd(HAnd* instruction) {
915 HandleBinaryOp(instruction);
916}
917
918void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) {
919 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +0100920}
921
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000922void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
923 LocationSummary* locations =
924 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
925 locations->SetInAt(0, Location::RequiresRegister());
926 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
927 locations->SetOut(Location::RequiresRegister());
928}
929
930void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
931 LocationSummary* locations = instruction->GetLocations();
932 Primitive::Type type = instruction->GetType();
933 Register obj = InputRegisterAt(instruction, 0);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000934 Location index = locations->InAt(1);
935 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value();
936 MemOperand source(obj);
Alexandre Rames67555f72014-11-18 10:55:16 +0000937 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000938
939 if (index.IsConstant()) {
940 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
941 source = MemOperand(obj, offset);
942 } else {
943 Register temp = temps.AcquireSameSizeAs(obj);
944 Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
945 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type)));
946 source = MemOperand(temp, offset);
947 }
948
Alexandre Rames67555f72014-11-18 10:55:16 +0000949 codegen_->Load(type, OutputCPURegister(instruction), source);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000950}
951
Alexandre Rames5319def2014-10-23 10:03:10 +0100952void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
953 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
954 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +0000955 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +0100956}
957
958void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
959 __ Ldr(OutputRegister(instruction),
960 HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset()));
961}
962
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000963void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
964 Primitive::Type value_type = instruction->GetComponentType();
965 bool is_object = value_type == Primitive::kPrimNot;
966 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
967 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
968 if (is_object) {
969 InvokeRuntimeCallingConvention calling_convention;
970 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
971 locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
972 locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
973 } else {
974 locations->SetInAt(0, Location::RequiresRegister());
975 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
976 locations->SetInAt(2, Location::RequiresRegister());
977 }
978}
979
980void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
981 Primitive::Type value_type = instruction->GetComponentType();
982 if (value_type == Primitive::kPrimNot) {
Alexandre Rames67555f72014-11-18 10:55:16 +0000983 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
984
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000985 } else {
986 LocationSummary* locations = instruction->GetLocations();
987 Register obj = InputRegisterAt(instruction, 0);
Alexandre Rames67555f72014-11-18 10:55:16 +0000988 CPURegister value = InputCPURegisterAt(instruction, 2);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000989 Location index = locations->InAt(1);
990 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
991 MemOperand destination(obj);
Alexandre Rames67555f72014-11-18 10:55:16 +0000992 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000993
994 if (index.IsConstant()) {
995 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
996 destination = MemOperand(obj, offset);
997 } else {
998 Register temp = temps.AcquireSameSizeAs(obj);
999 Register index_reg = InputRegisterAt(instruction, 1);
1000 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type)));
1001 destination = MemOperand(temp, offset);
1002 }
1003
1004 codegen_->Store(value_type, value, destination);
1005 }
1006}
1007
Alexandre Rames67555f72014-11-18 10:55:16 +00001008void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1009 LocationSummary* locations =
1010 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1011 locations->SetInAt(0, Location::RequiresRegister());
1012 locations->SetInAt(1, Location::RequiresRegister());
1013 if (instruction->HasUses()) {
1014 locations->SetOut(Location::SameAsFirstInput());
1015 }
1016}
1017
1018void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1019 BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64();
1020 codegen_->AddSlowPath(slow_path);
1021
1022 __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
1023 __ B(slow_path->GetEntryLabel(), hs);
1024}
1025
1026void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
1027 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1028 instruction, LocationSummary::kCallOnSlowPath);
1029 locations->SetInAt(0, Location::RequiresRegister());
1030 locations->SetInAt(1, Location::RequiresRegister());
1031}
1032
1033void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
1034 UseScratchRegisterScope temps(GetVIXLAssembler());
1035 Register obj = InputRegisterAt(instruction, 0);;
1036 Register cls = InputRegisterAt(instruction, 1);;
1037 Register temp = temps.AcquireW();
1038
1039 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64();
1040 codegen_->AddSlowPath(slow_path);
1041
1042 // TODO: avoid this check if we know obj is not null.
1043 __ Cbz(obj, slow_path->GetExitLabel());
1044 // Compare the class of `obj` with `cls`.
1045 __ Ldr(temp, HeapOperand(obj, mirror::Object::ClassOffset()));
1046 __ Cmp(temp, cls);
1047 __ B(ne, slow_path->GetEntryLabel());
1048 __ Bind(slow_path->GetExitLabel());
1049}
1050
1051void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) {
1052 LocationSummary* locations =
1053 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
1054 locations->SetInAt(0, Location::RequiresRegister());
1055 if (check->HasUses()) {
1056 locations->SetOut(Location::SameAsFirstInput());
1057 }
1058}
1059
1060void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) {
1061 // We assume the class is not null.
1062 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
1063 check->GetLoadClass(), check, check->GetDexPc(), true);
1064 codegen_->AddSlowPath(slow_path);
1065 GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
1066}
1067
Alexandre Rames5319def2014-10-23 10:03:10 +01001068void LocationsBuilderARM64::VisitCompare(HCompare* instruction) {
1069 LocationSummary* locations =
1070 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1071 locations->SetInAt(0, Location::RequiresRegister());
1072 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001073 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001074}
1075
1076void InstructionCodeGeneratorARM64::VisitCompare(HCompare* instruction) {
1077 Primitive::Type in_type = instruction->InputAt(0)->GetType();
1078
1079 DCHECK_EQ(in_type, Primitive::kPrimLong);
1080 switch (in_type) {
1081 case Primitive::kPrimLong: {
1082 vixl::Label done;
1083 Register result = OutputRegister(instruction);
1084 Register left = InputRegisterAt(instruction, 0);
1085 Operand right = InputOperandAt(instruction, 1);
Alexandre Rames67555f72014-11-18 10:55:16 +00001086 __ Subs(result.X(), left, right);
Alexandre Rames5319def2014-10-23 10:03:10 +01001087 __ B(eq, &done);
1088 __ Mov(result, 1);
1089 __ Cneg(result, result, le);
1090 __ Bind(&done);
1091 break;
1092 }
1093 default:
1094 LOG(FATAL) << "Unimplemented compare type " << in_type;
1095 }
1096}
1097
1098void LocationsBuilderARM64::VisitCondition(HCondition* instruction) {
1099 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1100 locations->SetInAt(0, Location::RequiresRegister());
1101 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1102 if (instruction->NeedsMaterialization()) {
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001103 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001104 }
1105}
1106
1107void InstructionCodeGeneratorARM64::VisitCondition(HCondition* instruction) {
1108 if (!instruction->NeedsMaterialization()) {
1109 return;
1110 }
1111
1112 LocationSummary* locations = instruction->GetLocations();
1113 Register lhs = InputRegisterAt(instruction, 0);
1114 Operand rhs = InputOperandAt(instruction, 1);
1115 Register res = RegisterFrom(locations->Out(), instruction->GetType());
1116 Condition cond = ARM64Condition(instruction->GetCondition());
1117
1118 __ Cmp(lhs, rhs);
1119 __ Csel(res, vixl::Assembler::AppropriateZeroRegFor(res), Operand(1), InvertCondition(cond));
1120}
1121
1122#define FOR_EACH_CONDITION_INSTRUCTION(M) \
1123 M(Equal) \
1124 M(NotEqual) \
1125 M(LessThan) \
1126 M(LessThanOrEqual) \
1127 M(GreaterThan) \
1128 M(GreaterThanOrEqual)
1129#define DEFINE_CONDITION_VISITORS(Name) \
1130void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } \
1131void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }
1132FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
Alexandre Rames67555f72014-11-18 10:55:16 +00001133#undef DEFINE_CONDITION_VISITORS
Alexandre Rames5319def2014-10-23 10:03:10 +01001134#undef FOR_EACH_CONDITION_INSTRUCTION
1135
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001136void LocationsBuilderARM64::VisitDiv(HDiv* div) {
1137 LocationSummary* locations =
1138 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
1139 switch (div->GetResultType()) {
1140 case Primitive::kPrimInt:
1141 case Primitive::kPrimLong:
1142 locations->SetInAt(0, Location::RequiresRegister());
1143 locations->SetInAt(1, Location::RequiresRegister());
1144 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1145 break;
1146
1147 case Primitive::kPrimFloat:
1148 case Primitive::kPrimDouble:
1149 locations->SetInAt(0, Location::RequiresFpuRegister());
1150 locations->SetInAt(1, Location::RequiresFpuRegister());
1151 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1152 break;
1153
1154 default:
1155 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1156 }
1157}
1158
1159void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
1160 Primitive::Type type = div->GetResultType();
1161 switch (type) {
1162 case Primitive::kPrimInt:
1163 case Primitive::kPrimLong:
1164 __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
1165 break;
1166
1167 case Primitive::kPrimFloat:
1168 case Primitive::kPrimDouble:
1169 __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
1170 break;
1171
1172 default:
1173 LOG(FATAL) << "Unexpected div type " << type;
1174 }
1175}
1176
Alexandre Rames67555f72014-11-18 10:55:16 +00001177void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1178 LocationSummary* locations =
1179 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1180 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
1181 if (instruction->HasUses()) {
1182 locations->SetOut(Location::SameAsFirstInput());
1183 }
1184}
1185
1186void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1187 SlowPathCodeARM64* slow_path =
1188 new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction);
1189 codegen_->AddSlowPath(slow_path);
1190 Location value = instruction->GetLocations()->InAt(0);
1191
1192 if (value.IsConstant()) {
1193 int64_t divisor = Int64ConstantFrom(value);
1194 if (divisor == 0) {
1195 __ B(slow_path->GetEntryLabel());
1196 } else {
1197 LOG(FATAL) << "Divisions by non-null constants should have been optimized away.";
1198 }
1199 } else {
1200 __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
1201 }
1202}
1203
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001204void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1205 LocationSummary* locations =
1206 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1207 locations->SetOut(Location::ConstantLocation(constant));
1208}
1209
1210void InstructionCodeGeneratorARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1211 UNUSED(constant);
1212 // Will be generated at use site.
1213}
1214
Alexandre Rames5319def2014-10-23 10:03:10 +01001215void LocationsBuilderARM64::VisitExit(HExit* exit) {
1216 exit->SetLocations(nullptr);
1217}
1218
1219void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001220 UNUSED(exit);
Alexandre Rames5319def2014-10-23 10:03:10 +01001221 if (kIsDebugBuild) {
1222 down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable");
Alexandre Rames67555f72014-11-18 10:55:16 +00001223 __ Brk(__LINE__); // TODO: Introduce special markers for such code locations.
Alexandre Rames5319def2014-10-23 10:03:10 +01001224 }
1225}
1226
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001227void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) {
1228 LocationSummary* locations =
1229 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1230 locations->SetOut(Location::ConstantLocation(constant));
1231}
1232
1233void InstructionCodeGeneratorARM64::VisitFloatConstant(HFloatConstant* constant) {
1234 UNUSED(constant);
1235 // Will be generated at use site.
1236}
1237
Alexandre Rames5319def2014-10-23 10:03:10 +01001238void LocationsBuilderARM64::VisitGoto(HGoto* got) {
1239 got->SetLocations(nullptr);
1240}
1241
1242void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
1243 HBasicBlock* successor = got->GetSuccessor();
1244 // TODO: Support for suspend checks emission.
1245 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
1246 __ B(codegen_->GetLabelOf(successor));
1247 }
1248}
1249
1250void LocationsBuilderARM64::VisitIf(HIf* if_instr) {
1251 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1252 HInstruction* cond = if_instr->InputAt(0);
1253 DCHECK(cond->IsCondition());
1254 if (cond->AsCondition()->NeedsMaterialization()) {
1255 locations->SetInAt(0, Location::RequiresRegister());
1256 }
1257}
1258
1259void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) {
1260 HInstruction* cond = if_instr->InputAt(0);
1261 DCHECK(cond->IsCondition());
1262 HCondition* condition = cond->AsCondition();
1263 vixl::Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1264 vixl::Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1265
1266 // TODO: Support constant condition input in VisitIf.
1267
1268 if (condition->NeedsMaterialization()) {
1269 // The condition instruction has been materialized, compare the output to 0.
1270 Location cond_val = if_instr->GetLocations()->InAt(0);
1271 DCHECK(cond_val.IsRegister());
1272 __ Cbnz(InputRegisterAt(if_instr, 0), true_target);
1273
1274 } else {
1275 // The condition instruction has not been materialized, use its inputs as
1276 // the comparison and its condition as the branch condition.
1277 Register lhs = InputRegisterAt(condition, 0);
1278 Operand rhs = InputOperandAt(condition, 1);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001279 Condition arm64_cond = ARM64Condition(condition->GetCondition());
1280 if ((arm64_cond == eq || arm64_cond == ne) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
1281 if (arm64_cond == eq) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001282 __ Cbz(lhs, true_target);
1283 } else {
1284 __ Cbnz(lhs, true_target);
1285 }
1286 } else {
1287 __ Cmp(lhs, rhs);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001288 __ B(arm64_cond, true_target);
Alexandre Rames5319def2014-10-23 10:03:10 +01001289 }
1290 }
1291
1292 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
1293 __ B(false_target);
1294 }
1295}
1296
1297void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1298 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1299 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001300 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001301}
1302
1303void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001304 MemOperand field = MemOperand(InputRegisterAt(instruction, 0),
1305 instruction->GetFieldOffset().Uint32Value());
Alexandre Rames67555f72014-11-18 10:55:16 +00001306 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
Alexandre Rames5319def2014-10-23 10:03:10 +01001307}
1308
1309void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1310 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1311 locations->SetInAt(0, Location::RequiresRegister());
1312 locations->SetInAt(1, Location::RequiresRegister());
1313}
1314
1315void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001316 Primitive::Type field_type = instruction->GetFieldType();
Alexandre Rames67555f72014-11-18 10:55:16 +00001317 CPURegister value = InputCPURegisterAt(instruction, 1);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001318 Register obj = InputRegisterAt(instruction, 0);
1319 codegen_->Store(field_type, value, MemOperand(obj, instruction->GetFieldOffset().Uint32Value()));
1320 if (field_type == Primitive::kPrimNot) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001321 codegen_->MarkGCCard(obj, Register(value));
Alexandre Rames5319def2014-10-23 10:03:10 +01001322 }
1323}
1324
Alexandre Rames67555f72014-11-18 10:55:16 +00001325void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
1326 LocationSummary::CallKind call_kind =
1327 instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
1328 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
1329 locations->SetInAt(0, Location::RequiresRegister());
1330 locations->SetInAt(1, Location::RequiresRegister());
1331 locations->SetOut(Location::RequiresRegister(), true); // The output does overlap inputs.
1332}
1333
1334void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
1335 LocationSummary* locations = instruction->GetLocations();
1336 Register obj = InputRegisterAt(instruction, 0);;
1337 Register cls = InputRegisterAt(instruction, 1);;
1338 Register out = OutputRegister(instruction);
1339
1340 vixl::Label done;
1341
1342 // Return 0 if `obj` is null.
1343 // TODO: Avoid this check if we know `obj` is not null.
1344 __ Mov(out, 0);
1345 __ Cbz(obj, &done);
1346
1347 // Compare the class of `obj` with `cls`.
1348 __ Ldr(out, MemOperand(obj, mirror::Object::ClassOffset().Int32Value()));
1349 __ Cmp(out, cls);
1350 if (instruction->IsClassFinal()) {
1351 // Classes must be equal for the instanceof to succeed.
1352 __ Cset(out, eq);
1353 } else {
1354 // If the classes are not equal, we go into a slow path.
1355 DCHECK(locations->OnlyCallsOnSlowPath());
1356 SlowPathCodeARM64* slow_path =
1357 new (GetGraph()->GetArena()) TypeCheckSlowPathARM64();
1358 codegen_->AddSlowPath(slow_path);
1359 __ B(ne, slow_path->GetEntryLabel());
1360 __ Mov(out, 1);
1361 __ Bind(slow_path->GetExitLabel());
1362 }
1363
1364 __ Bind(&done);
1365}
1366
Alexandre Rames5319def2014-10-23 10:03:10 +01001367void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
1368 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1369 locations->SetOut(Location::ConstantLocation(constant));
1370}
1371
1372void InstructionCodeGeneratorARM64::VisitIntConstant(HIntConstant* constant) {
1373 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001374 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001375}
1376
Alexandre Rames5319def2014-10-23 10:03:10 +01001377void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
1378 LocationSummary* locations =
1379 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
1380 locations->AddTemp(LocationFrom(x0));
1381
1382 InvokeDexCallingConventionVisitor calling_convention_visitor;
1383 for (size_t i = 0; i < invoke->InputCount(); i++) {
1384 HInstruction* input = invoke->InputAt(i);
1385 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1386 }
1387
1388 Primitive::Type return_type = invoke->GetType();
1389 if (return_type != Primitive::kPrimVoid) {
1390 locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type));
1391 }
1392}
1393
Alexandre Rames67555f72014-11-18 10:55:16 +00001394void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1395 HandleInvoke(invoke);
1396}
1397
1398void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1399 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1400 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1401 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1402 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1403 Location receiver = invoke->GetLocations()->InAt(0);
1404 Offset class_offset = mirror::Object::ClassOffset();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001405 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
Alexandre Rames67555f72014-11-18 10:55:16 +00001406
1407 // The register ip1 is required to be used for the hidden argument in
1408 // art_quick_imt_conflict_trampoline, so prevent VIXL from using it.
1409 UseScratchRegisterScope scratch_scope(GetVIXLAssembler());
1410 scratch_scope.Exclude(ip1);
1411 __ Mov(ip1, invoke->GetDexMethodIndex());
1412
1413 // temp = object->GetClass();
1414 if (receiver.IsStackSlot()) {
1415 __ Ldr(temp, StackOperandFrom(receiver));
1416 __ Ldr(temp, HeapOperand(temp, class_offset));
1417 } else {
1418 __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
1419 }
1420 // temp = temp->GetImtEntryAt(method_offset);
1421 __ Ldr(temp, HeapOperand(temp, method_offset));
1422 // lr = temp->GetEntryPoint();
1423 __ Ldr(lr, HeapOperand(temp, entry_point));
1424 // lr();
1425 __ Blr(lr);
1426 DCHECK(!codegen_->IsLeafMethod());
1427 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1428}
1429
1430void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1431 HandleInvoke(invoke);
1432}
1433
1434void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
1435 HandleInvoke(invoke);
1436}
1437
Alexandre Rames5319def2014-10-23 10:03:10 +01001438void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
1439 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1440 // Make sure that ArtMethod* is passed in W0 as per the calling convention
1441 DCHECK(temp.Is(w0));
1442 size_t index_in_cache = mirror::Array::DataOffset(kHeapRefSize).SizeValue() +
1443 invoke->GetIndexInDexCache() * kHeapRefSize;
1444
1445 // TODO: Implement all kinds of calls:
1446 // 1) boot -> boot
1447 // 2) app -> boot
1448 // 3) app -> app
1449 //
1450 // Currently we implement the app -> app logic, which looks up in the resolve cache.
1451
1452 // temp = method;
Alexandre Rames67555f72014-11-18 10:55:16 +00001453 codegen_->LoadCurrentMethod(temp);
Alexandre Rames5319def2014-10-23 10:03:10 +01001454 // temp = temp->dex_cache_resolved_methods_;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001455 __ Ldr(temp, MemOperand(temp.X(),
1456 mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
Alexandre Rames5319def2014-10-23 10:03:10 +01001457 // temp = temp[index_in_cache];
1458 __ Ldr(temp, MemOperand(temp.X(), index_in_cache));
1459 // lr = temp->entry_point_from_quick_compiled_code_;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001460 __ Ldr(lr, MemOperand(temp.X(),
Mathieu Chartier2d721012014-11-10 11:08:06 -08001461 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001462 kArm64WordSize).SizeValue()));
Alexandre Rames5319def2014-10-23 10:03:10 +01001463 // lr();
1464 __ Blr(lr);
1465
1466 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1467 DCHECK(!codegen_->IsLeafMethod());
1468}
1469
1470void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1471 LocationSummary* locations = invoke->GetLocations();
1472 Location receiver = locations->InAt(0);
1473 Register temp = XRegisterFrom(invoke->GetLocations()->GetTemp(0));
1474 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1475 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1476 Offset class_offset = mirror::Object::ClassOffset();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001477 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
Alexandre Rames5319def2014-10-23 10:03:10 +01001478
1479 // temp = object->GetClass();
1480 if (receiver.IsStackSlot()) {
1481 __ Ldr(temp.W(), MemOperand(sp, receiver.GetStackIndex()));
1482 __ Ldr(temp.W(), MemOperand(temp, class_offset.SizeValue()));
1483 } else {
1484 DCHECK(receiver.IsRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00001485 __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001486 }
1487 // temp = temp->GetMethodAt(method_offset);
1488 __ Ldr(temp.W(), MemOperand(temp, method_offset));
1489 // lr = temp->GetEntryPoint();
1490 __ Ldr(lr, MemOperand(temp, entry_point.SizeValue()));
1491 // lr();
1492 __ Blr(lr);
1493 DCHECK(!codegen_->IsLeafMethod());
1494 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1495}
1496
Alexandre Rames67555f72014-11-18 10:55:16 +00001497void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
1498 LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
1499 : LocationSummary::kNoCall;
1500 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
1501 locations->SetOut(Location::RequiresRegister());
1502}
1503
1504void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
1505 Register out = OutputRegister(cls);
1506 if (cls->IsReferrersClass()) {
1507 DCHECK(!cls->CanCallRuntime());
1508 DCHECK(!cls->MustGenerateClinitCheck());
1509 codegen_->LoadCurrentMethod(out);
1510 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
1511 } else {
1512 DCHECK(cls->CanCallRuntime());
1513 codegen_->LoadCurrentMethod(out);
1514 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset()));
1515 __ Ldr(out, MemOperand(out.X(), CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
1516
1517 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
1518 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
1519 codegen_->AddSlowPath(slow_path);
1520 __ Cbz(out, slow_path->GetEntryLabel());
1521 if (cls->MustGenerateClinitCheck()) {
1522 GenerateClassInitializationCheck(slow_path, out);
1523 } else {
1524 __ Bind(slow_path->GetExitLabel());
1525 }
1526 }
1527}
1528
1529void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
1530 LocationSummary* locations =
1531 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
1532 locations->SetOut(Location::RequiresRegister());
1533}
1534
1535void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
1536 MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
1537 __ Ldr(OutputRegister(instruction), exception);
1538 __ Str(wzr, exception);
1539}
1540
Alexandre Rames5319def2014-10-23 10:03:10 +01001541void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
1542 load->SetLocations(nullptr);
1543}
1544
1545void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) {
1546 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001547 UNUSED(load);
Alexandre Rames5319def2014-10-23 10:03:10 +01001548}
1549
Alexandre Rames67555f72014-11-18 10:55:16 +00001550void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
1551 LocationSummary* locations =
1552 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
1553 locations->SetOut(Location::RequiresRegister());
1554}
1555
1556void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
1557 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
1558 codegen_->AddSlowPath(slow_path);
1559
1560 Register out = OutputRegister(load);
1561 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08001562 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
1563 __ Ldr(out, HeapOperand(out, mirror::Class::DexCacheStringsOffset()));
Alexandre Rames67555f72014-11-18 10:55:16 +00001564 __ Ldr(out, MemOperand(out.X(), CodeGenerator::GetCacheOffset(load->GetStringIndex())));
1565 __ Cbz(out, slow_path->GetEntryLabel());
1566 __ Bind(slow_path->GetExitLabel());
1567}
1568
Alexandre Rames5319def2014-10-23 10:03:10 +01001569void LocationsBuilderARM64::VisitLocal(HLocal* local) {
1570 local->SetLocations(nullptr);
1571}
1572
1573void InstructionCodeGeneratorARM64::VisitLocal(HLocal* local) {
1574 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1575}
1576
1577void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
1578 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1579 locations->SetOut(Location::ConstantLocation(constant));
1580}
1581
1582void InstructionCodeGeneratorARM64::VisitLongConstant(HLongConstant* constant) {
1583 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001584 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001585}
1586
Alexandre Rames67555f72014-11-18 10:55:16 +00001587void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
1588 LocationSummary* locations =
1589 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1590 InvokeRuntimeCallingConvention calling_convention;
1591 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
1592}
1593
1594void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
1595 codegen_->InvokeRuntime(instruction->IsEnter()
1596 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
1597 instruction,
1598 instruction->GetDexPc());
1599}
1600
Alexandre Rames42d641b2014-10-27 14:00:51 +00001601void LocationsBuilderARM64::VisitMul(HMul* mul) {
1602 LocationSummary* locations =
1603 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1604 switch (mul->GetResultType()) {
1605 case Primitive::kPrimInt:
1606 case Primitive::kPrimLong:
1607 locations->SetInAt(0, Location::RequiresRegister());
1608 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001609 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00001610 break;
1611
1612 case Primitive::kPrimFloat:
1613 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001614 locations->SetInAt(0, Location::RequiresFpuRegister());
1615 locations->SetInAt(1, Location::RequiresFpuRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00001616 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00001617 break;
1618
1619 default:
1620 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1621 }
1622}
1623
1624void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) {
1625 switch (mul->GetResultType()) {
1626 case Primitive::kPrimInt:
1627 case Primitive::kPrimLong:
1628 __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
1629 break;
1630
1631 case Primitive::kPrimFloat:
1632 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001633 __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1));
Alexandre Rames42d641b2014-10-27 14:00:51 +00001634 break;
1635
1636 default:
1637 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1638 }
1639}
1640
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001641void LocationsBuilderARM64::VisitNeg(HNeg* neg) {
1642 LocationSummary* locations =
1643 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1644 switch (neg->GetResultType()) {
1645 case Primitive::kPrimInt:
Alexandre Rames67555f72014-11-18 10:55:16 +00001646 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001647 locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0)));
Alexandre Rames67555f72014-11-18 10:55:16 +00001648 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001649 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001650
1651 case Primitive::kPrimFloat:
1652 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +00001653 locations->SetInAt(0, Location::RequiresFpuRegister());
1654 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001655 break;
1656
1657 default:
1658 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1659 }
1660}
1661
1662void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
1663 switch (neg->GetResultType()) {
1664 case Primitive::kPrimInt:
1665 case Primitive::kPrimLong:
1666 __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
1667 break;
1668
1669 case Primitive::kPrimFloat:
1670 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +00001671 __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001672 break;
1673
1674 default:
1675 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1676 }
1677}
1678
1679void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) {
1680 LocationSummary* locations =
1681 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1682 InvokeRuntimeCallingConvention calling_convention;
1683 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
1684 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
1685 locations->SetOut(LocationFrom(x0));
1686 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(2)));
1687}
1688
1689void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
1690 LocationSummary* locations = instruction->GetLocations();
1691 InvokeRuntimeCallingConvention calling_convention;
1692 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
1693 DCHECK(type_index.Is(w0));
1694 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
1695 DCHECK(current_method.Is(w1));
Alexandre Rames67555f72014-11-18 10:55:16 +00001696 codegen_->LoadCurrentMethod(current_method);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001697 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +00001698 codegen_->InvokeRuntime(
1699 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001700}
1701
Alexandre Rames5319def2014-10-23 10:03:10 +01001702void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
1703 LocationSummary* locations =
1704 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1705 InvokeRuntimeCallingConvention calling_convention;
1706 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
1707 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
1708 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
1709}
1710
1711void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) {
1712 LocationSummary* locations = instruction->GetLocations();
1713 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
1714 DCHECK(type_index.Is(w0));
1715 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
1716 DCHECK(current_method.Is(w1));
Alexandre Rames67555f72014-11-18 10:55:16 +00001717 codegen_->LoadCurrentMethod(current_method);
Alexandre Rames5319def2014-10-23 10:03:10 +01001718 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +00001719 codegen_->InvokeRuntime(
1720 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
Alexandre Rames5319def2014-10-23 10:03:10 +01001721}
1722
1723void LocationsBuilderARM64::VisitNot(HNot* instruction) {
1724 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Alexandre Rames4e596512014-11-07 15:56:50 +00001725 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001726 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001727}
1728
1729void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
1730 switch (instruction->InputAt(0)->GetType()) {
1731 case Primitive::kPrimBoolean:
1732 __ Eor(OutputRegister(instruction), InputRegisterAt(instruction, 0), Operand(1));
1733 break;
1734
1735 case Primitive::kPrimInt:
Alexandre Rames5319def2014-10-23 10:03:10 +01001736 case Primitive::kPrimLong:
Roland Levillain55dcfb52014-10-24 18:09:09 +01001737 __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
Alexandre Rames5319def2014-10-23 10:03:10 +01001738 break;
1739
1740 default:
1741 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
1742 }
1743}
1744
1745void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
1746 LocationSummary* locations =
1747 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1748 locations->SetInAt(0, Location::RequiresRegister());
1749 if (instruction->HasUses()) {
1750 locations->SetOut(Location::SameAsFirstInput());
1751 }
1752}
1753
1754void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
1755 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction);
1756 codegen_->AddSlowPath(slow_path);
1757
1758 LocationSummary* locations = instruction->GetLocations();
1759 Location obj = locations->InAt(0);
1760 if (obj.IsRegister()) {
1761 __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel());
1762 } else {
1763 DCHECK(obj.IsConstant()) << obj;
1764 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1765 __ B(slow_path->GetEntryLabel());
1766 }
1767}
1768
Alexandre Rames67555f72014-11-18 10:55:16 +00001769void LocationsBuilderARM64::VisitOr(HOr* instruction) {
1770 HandleBinaryOp(instruction);
1771}
1772
1773void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) {
1774 HandleBinaryOp(instruction);
1775}
1776
Alexandre Rames5319def2014-10-23 10:03:10 +01001777void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
1778 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1779 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1780 if (location.IsStackSlot()) {
1781 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1782 } else if (location.IsDoubleStackSlot()) {
1783 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1784 }
1785 locations->SetOut(location);
1786}
1787
1788void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) {
1789 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001790 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001791}
1792
1793void LocationsBuilderARM64::VisitPhi(HPhi* instruction) {
1794 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1795 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1796 locations->SetInAt(i, Location::Any());
1797 }
1798 locations->SetOut(Location::Any());
1799}
1800
1801void InstructionCodeGeneratorARM64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001802 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001803 LOG(FATAL) << "Unreachable";
1804}
1805
1806void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
1807 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1808 Primitive::Type return_type = instruction->InputAt(0)->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001809 locations->SetInAt(0, ARM64ReturnLocation(return_type));
Alexandre Rames5319def2014-10-23 10:03:10 +01001810}
1811
1812void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001813 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001814 codegen_->GenerateFrameExit();
1815 __ Br(lr);
1816}
1817
1818void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) {
1819 instruction->SetLocations(nullptr);
1820}
1821
1822void InstructionCodeGeneratorARM64::VisitReturnVoid(HReturnVoid* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001823 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001824 codegen_->GenerateFrameExit();
1825 __ Br(lr);
1826}
1827
1828void LocationsBuilderARM64::VisitStoreLocal(HStoreLocal* store) {
1829 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
1830 Primitive::Type field_type = store->InputAt(1)->GetType();
1831 switch (field_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001832 case Primitive::kPrimNot:
Alexandre Rames5319def2014-10-23 10:03:10 +01001833 case Primitive::kPrimBoolean:
1834 case Primitive::kPrimByte:
1835 case Primitive::kPrimChar:
1836 case Primitive::kPrimShort:
1837 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001838 case Primitive::kPrimFloat:
Alexandre Rames5319def2014-10-23 10:03:10 +01001839 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1840 break;
1841
1842 case Primitive::kPrimLong:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001843 case Primitive::kPrimDouble:
Alexandre Rames5319def2014-10-23 10:03:10 +01001844 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1845 break;
1846
1847 default:
1848 LOG(FATAL) << "Unimplemented local type " << field_type;
1849 }
1850}
1851
1852void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001853 UNUSED(store);
Alexandre Rames5319def2014-10-23 10:03:10 +01001854}
1855
1856void LocationsBuilderARM64::VisitSub(HSub* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001857 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001858}
1859
1860void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001861 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001862}
1863
Alexandre Rames67555f72014-11-18 10:55:16 +00001864void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
1865 LocationSummary* locations =
1866 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1867 locations->SetInAt(0, Location::RequiresRegister());
1868 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1869}
1870
1871void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
1872 Register cls = InputRegisterAt(instruction, 0);
1873 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1874 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), MemOperand(cls, offset));
1875}
1876
1877void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001878 LocationSummary* locations =
1879 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1880 locations->SetInAt(0, Location::RequiresRegister());
1881 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Rames5319def2014-10-23 10:03:10 +01001882}
1883
Alexandre Rames67555f72014-11-18 10:55:16 +00001884void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
1885 CPURegister value = InputCPURegisterAt(instruction, 1);
1886 Register cls = InputRegisterAt(instruction, 0);
1887 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1888 Primitive::Type field_type = instruction->GetFieldType();
Alexandre Rames5319def2014-10-23 10:03:10 +01001889
Alexandre Rames67555f72014-11-18 10:55:16 +00001890 codegen_->Store(field_type, value, MemOperand(cls, offset));
1891 if (field_type == Primitive::kPrimNot) {
1892 codegen_->MarkGCCard(cls, Register(value));
1893 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001894}
1895
1896void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
1897 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1898}
1899
1900void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
1901 // TODO: Improve support for suspend checks.
1902 SuspendCheckSlowPathARM64* slow_path =
1903 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM64(instruction, nullptr);
1904 codegen_->AddSlowPath(slow_path);
1905
1906 __ Subs(wSuspend, wSuspend, 1);
1907 __ B(slow_path->GetEntryLabel(), le);
1908 __ Bind(slow_path->GetReturnLabel());
1909}
1910
1911void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
1912 temp->SetLocations(nullptr);
1913}
1914
1915void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) {
1916 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001917 UNUSED(temp);
Alexandre Rames5319def2014-10-23 10:03:10 +01001918}
1919
Alexandre Rames67555f72014-11-18 10:55:16 +00001920void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
1921 LocationSummary* locations =
1922 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1923 InvokeRuntimeCallingConvention calling_convention;
1924 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
1925}
1926
1927void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
1928 codegen_->InvokeRuntime(
1929 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
1930}
1931
1932void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
1933 LocationSummary* locations =
1934 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
1935 Primitive::Type input_type = conversion->GetInputType();
1936 Primitive::Type result_type = conversion->GetResultType();
1937 if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
1938 (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
1939 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
1940 }
1941
1942 if (IsFPType(input_type)) {
1943 locations->SetInAt(0, Location::RequiresFpuRegister());
1944 } else {
1945 locations->SetInAt(0, Location::RequiresRegister());
1946 }
1947
1948 if (IsFPType(result_type)) {
1949 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1950 } else {
1951 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1952 }
1953}
1954
1955void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
1956 Primitive::Type result_type = conversion->GetResultType();
1957 Primitive::Type input_type = conversion->GetInputType();
1958
1959 DCHECK_NE(input_type, result_type);
1960
1961 if (IsIntegralType(result_type) && IsIntegralType(input_type)) {
1962 int result_size = Primitive::ComponentSize(result_type);
1963 int input_size = Primitive::ComponentSize(input_type);
1964 int min_size = kBitsPerByte * std::min(result_size, input_size);
1965 if ((result_type == Primitive::kPrimChar) ||
1966 ((input_type == Primitive::kPrimChar) && (result_size > input_size))) {
1967 __ Ubfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, min_size);
1968 } else {
1969 __ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, min_size);
1970 }
1971 return;
1972 }
1973
1974 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
1975 << " to " << result_type;
1976}
1977
1978void LocationsBuilderARM64::VisitXor(HXor* instruction) {
1979 HandleBinaryOp(instruction);
1980}
1981
1982void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) {
1983 HandleBinaryOp(instruction);
1984}
1985
1986#undef __
1987#undef QUICK_ENTRY_POINT
1988
Alexandre Rames5319def2014-10-23 10:03:10 +01001989} // namespace arm64
1990} // namespace art