blob: 943f71f2743d001eb2ac4a2c135281aefe2d8721 [file] [log] [blame]
Alexandre Rames5319def2014-10-23 10:03:10 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_arm64.h"
18
19#include "entrypoints/quick/quick_entrypoints.h"
20#include "gc/accounting/card_table.h"
21#include "mirror/array-inl.h"
22#include "mirror/art_method.h"
23#include "mirror/class.h"
24#include "thread.h"
25#include "utils/arm64/assembler_arm64.h"
26#include "utils/assembler.h"
27#include "utils/stack_checks.h"
28
29
30using namespace vixl; // NOLINT(build/namespaces)
31
32#ifdef __
33#error "ARM64 Codegen VIXL macro-assembler macro already defined."
34#endif
35
36
37namespace art {
38
39namespace arm64 {
40
Serban Constantinescu02164b32014-11-13 14:05:07 +000041static constexpr bool kExplicitStackOverflowCheck = false;
Alexandre Rames5319def2014-10-23 10:03:10 +010042static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>);
43static constexpr int kCurrentMethodStackOffset = 0;
44
45namespace {
Alexandre Ramesa89086e2014-11-07 17:13:25 +000046
47bool IsFPType(Primitive::Type type) {
48 return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble;
49}
50
Alexandre Rames67555f72014-11-18 10:55:16 +000051bool IsIntegralType(Primitive::Type type) {
52 switch (type) {
53 case Primitive::kPrimByte:
54 case Primitive::kPrimChar:
55 case Primitive::kPrimShort:
56 case Primitive::kPrimInt:
57 case Primitive::kPrimLong:
58 return true;
59 default:
60 return false;
61 }
62}
63
Alexandre Ramesa89086e2014-11-07 17:13:25 +000064bool Is64BitType(Primitive::Type type) {
65 return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
66}
67
Alexandre Rames5319def2014-10-23 10:03:10 +010068// Convenience helpers to ease conversion to and from VIXL operands.
Alexandre Rames67555f72014-11-18 10:55:16 +000069static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32),
70 "Unexpected values for register codes.");
Alexandre Rames5319def2014-10-23 10:03:10 +010071
72int VIXLRegCodeFromART(int code) {
Alexandre Rames5319def2014-10-23 10:03:10 +010073 if (code == SP) {
74 return vixl::kSPRegInternalCode;
75 }
76 if (code == XZR) {
77 return vixl::kZeroRegCode;
78 }
79 return code;
80}
81
82int ARTRegCodeFromVIXL(int code) {
Alexandre Rames5319def2014-10-23 10:03:10 +010083 if (code == vixl::kSPRegInternalCode) {
84 return SP;
85 }
86 if (code == vixl::kZeroRegCode) {
87 return XZR;
88 }
89 return code;
90}
91
92Register XRegisterFrom(Location location) {
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
Serban Constantinescu02164b32014-11-13 14:05:07 +0000170MemOperand HeapOperand(const Register& base, size_t offset = 0) {
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
Serban Constantinescu02164b32014-11-13 14:05:07 +0000396class StackOverflowCheckSlowPathARM64 : public SlowPathCodeARM64 {
397 public:
398 StackOverflowCheckSlowPathARM64() {}
399
400 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
401 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
402 __ Bind(GetEntryLabel());
403 arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowStackOverflow), nullptr, 0);
404 }
405
406 private:
407 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM64);
408};
409
Alexandre Rames5319def2014-10-23 10:03:10 +0100410class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 {
411 public:
412 explicit SuspendCheckSlowPathARM64(HSuspendCheck* instruction,
413 HBasicBlock* successor)
414 : instruction_(instruction), successor_(successor) {}
415
Alexandre Rames67555f72014-11-18 10:55:16 +0000416 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
417 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100418 __ Bind(GetEntryLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000419 codegen->SaveLiveRegisters(instruction_->GetLocations());
420 arm64_codegen->InvokeRuntime(
421 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
422 codegen->RestoreLiveRegisters(instruction_->GetLocations());
423 if (successor_ == nullptr) {
424 __ B(GetReturnLabel());
425 } else {
426 __ B(arm64_codegen->GetLabelOf(successor_));
427 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100428 }
429
430 vixl::Label* GetReturnLabel() {
431 DCHECK(successor_ == nullptr);
432 return &return_label_;
433 }
434
Alexandre Rames5319def2014-10-23 10:03:10 +0100435 private:
436 HSuspendCheck* const instruction_;
437 // If not null, the block to branch to after the suspend check.
438 HBasicBlock* const successor_;
439
440 // If `successor_` is null, the label to branch to after the suspend check.
441 vixl::Label return_label_;
442
443 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
444};
445
Alexandre Rames67555f72014-11-18 10:55:16 +0000446class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
447 public:
448 TypeCheckSlowPathARM64() {}
449
450 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
451 __ Bind(GetEntryLabel());
452 __ Brk(__LINE__); // TODO: Unimplemented TypeCheckSlowPathARM64.
Serban Constantinescu02164b32014-11-13 14:05:07 +0000453 __ B(GetExitLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000454 }
455
456 private:
457 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64);
458};
459
Alexandre Rames5319def2014-10-23 10:03:10 +0100460#undef __
461
462Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
463 Location next_location;
464 if (type == Primitive::kPrimVoid) {
465 LOG(FATAL) << "Unreachable type " << type;
466 }
467
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000468 if (IsFPType(type) && (fp_index_ < calling_convention.GetNumberOfFpuRegisters())) {
469 next_location = LocationFrom(calling_convention.GetFpuRegisterAt(fp_index_++));
470 } else if (!IsFPType(type) && (gp_index_ < calling_convention.GetNumberOfRegisters())) {
471 next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++));
472 } else {
473 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
474 next_location = Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
475 : Location::StackSlot(stack_offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100476 }
477
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000478 // Space on the stack is reserved for all arguments.
479 stack_index_ += Is64BitType(type) ? 2 : 1;
Alexandre Rames5319def2014-10-23 10:03:10 +0100480 return next_location;
481}
482
483CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph)
484 : CodeGenerator(graph,
485 kNumberOfAllocatableRegisters,
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000486 kNumberOfAllocatableFPRegisters,
Alexandre Rames5319def2014-10-23 10:03:10 +0100487 kNumberOfAllocatableRegisterPairs),
488 block_labels_(nullptr),
489 location_builder_(graph, this),
490 instruction_visitor_(graph, this) {}
491
Alexandre Rames67555f72014-11-18 10:55:16 +0000492#undef __
493#define __ GetVIXLAssembler()->
Alexandre Rames5319def2014-10-23 10:03:10 +0100494
Serban Constantinescu32f5b4d2014-11-25 20:05:46 +0000495void CodeGeneratorARM64::Finalize(CodeAllocator* allocator) {
496 // Ensure we emit the literal pool.
497 __ FinalizeCode();
498 CodeGenerator::Finalize(allocator);
499}
500
Alexandre Rames5319def2014-10-23 10:03:10 +0100501void CodeGeneratorARM64::GenerateFrameEntry() {
Serban Constantinescu02164b32014-11-13 14:05:07 +0000502 bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kArm64) || !IsLeafMethod();
503 if (do_overflow_check) {
504 UseScratchRegisterScope temps(GetVIXLAssembler());
505 Register temp = temps.AcquireX();
506 if (kExplicitStackOverflowCheck) {
507 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM64();
508 AddSlowPath(slow_path);
509
510 __ Ldr(temp, MemOperand(tr, Thread::StackEndOffset<kArm64WordSize>().Int32Value()));
511 __ Cmp(sp, temp);
512 __ B(lo, slow_path->GetEntryLabel());
513 } else {
514 __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
515 __ Ldr(wzr, MemOperand(temp, 0));
516 RecordPcInfo(nullptr, 0);
517 }
518 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100519
520 CPURegList preserved_regs = GetFramePreservedRegisters();
521 int frame_size = GetFrameSize();
522 core_spill_mask_ |= preserved_regs.list();
523
524 __ Str(w0, MemOperand(sp, -frame_size, PreIndex));
525 __ PokeCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
526
527 // Stack layout:
528 // sp[frame_size - 8] : lr.
529 // ... : other preserved registers.
530 // sp[frame_size - regs_size]: first preserved register.
531 // ... : reserved frame space.
Alexandre Rames67555f72014-11-18 10:55:16 +0000532 // sp[0] : current method.
Alexandre Rames5319def2014-10-23 10:03:10 +0100533}
534
535void CodeGeneratorARM64::GenerateFrameExit() {
536 int frame_size = GetFrameSize();
537 CPURegList preserved_regs = GetFramePreservedRegisters();
538 __ PeekCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
539 __ Drop(frame_size);
540}
541
542void CodeGeneratorARM64::Bind(HBasicBlock* block) {
543 __ Bind(GetLabelOf(block));
544}
545
Alexandre Rames5319def2014-10-23 10:03:10 +0100546void CodeGeneratorARM64::Move(HInstruction* instruction,
547 Location location,
548 HInstruction* move_for) {
549 LocationSummary* locations = instruction->GetLocations();
550 if (locations != nullptr && locations->Out().Equals(location)) {
551 return;
552 }
553
554 Primitive::Type type = instruction->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000555 DCHECK_NE(type, Primitive::kPrimVoid);
Alexandre Rames5319def2014-10-23 10:03:10 +0100556
557 if (instruction->IsIntConstant() || instruction->IsLongConstant()) {
558 int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue()
559 : instruction->AsLongConstant()->GetValue();
560 if (location.IsRegister()) {
561 Register dst = RegisterFrom(location, type);
562 DCHECK((instruction->IsIntConstant() && dst.Is32Bits()) ||
563 (instruction->IsLongConstant() && dst.Is64Bits()));
564 __ Mov(dst, value);
565 } else {
566 DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
Alexandre Rames67555f72014-11-18 10:55:16 +0000567 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100568 Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
569 __ Mov(temp, value);
570 __ Str(temp, StackOperandFrom(location));
571 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000572 } else if (instruction->IsTemporary()) {
573 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
574 MoveHelper(location, temp_location, type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100575 } else if (instruction->IsLoadLocal()) {
576 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000577 if (Is64BitType(type)) {
578 MoveHelper(location, Location::DoubleStackSlot(stack_slot), type);
579 } else {
580 MoveHelper(location, Location::StackSlot(stack_slot), type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100581 }
582
583 } else {
584 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
585 MoveHelper(location, locations->Out(), type);
586 }
587}
588
589size_t CodeGeneratorARM64::FrameEntrySpillSize() const {
590 return GetFramePreservedRegistersSize();
591}
592
593Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const {
594 Primitive::Type type = load->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000595
Alexandre Rames5319def2014-10-23 10:03:10 +0100596 switch (type) {
597 case Primitive::kPrimNot:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000598 case Primitive::kPrimInt:
599 case Primitive::kPrimFloat:
600 return Location::StackSlot(GetStackSlot(load->GetLocal()));
601
602 case Primitive::kPrimLong:
603 case Primitive::kPrimDouble:
604 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
605
Alexandre Rames5319def2014-10-23 10:03:10 +0100606 case Primitive::kPrimBoolean:
607 case Primitive::kPrimByte:
608 case Primitive::kPrimChar:
609 case Primitive::kPrimShort:
Alexandre Rames5319def2014-10-23 10:03:10 +0100610 case Primitive::kPrimVoid:
Alexandre Rames5319def2014-10-23 10:03:10 +0100611 LOG(FATAL) << "Unexpected type " << type;
612 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000613
Alexandre Rames5319def2014-10-23 10:03:10 +0100614 LOG(FATAL) << "Unreachable";
615 return Location::NoLocation();
616}
617
618void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
Alexandre Rames67555f72014-11-18 10:55:16 +0000619 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100620 Register card = temps.AcquireX();
Serban Constantinescu02164b32014-11-13 14:05:07 +0000621 Register temp = temps.AcquireW(); // Index within the CardTable - 32bit.
Alexandre Rames5319def2014-10-23 10:03:10 +0100622 vixl::Label done;
623 __ Cbz(value, &done);
624 __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
625 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
Serban Constantinescu02164b32014-11-13 14:05:07 +0000626 __ Strb(card, MemOperand(card, temp.X()));
Alexandre Rames5319def2014-10-23 10:03:10 +0100627 __ Bind(&done);
628}
629
630void CodeGeneratorARM64::SetupBlockedRegisters() const {
631 // Block reserved registers:
632 // ip0 (VIXL temporary)
633 // ip1 (VIXL temporary)
Serban Constantinescu02164b32014-11-13 14:05:07 +0000634 // tr
Alexandre Rames5319def2014-10-23 10:03:10 +0100635 // lr
636 // sp is not part of the allocatable registers, so we don't need to block it.
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000637 // TODO: Avoid blocking callee-saved registers, and instead preserve them
638 // where necessary.
Alexandre Rames5319def2014-10-23 10:03:10 +0100639 CPURegList reserved_core_registers = vixl_reserved_core_registers;
640 reserved_core_registers.Combine(runtime_reserved_core_registers);
Alexandre Rames5319def2014-10-23 10:03:10 +0100641 reserved_core_registers.Combine(quick_callee_saved_registers);
642 while (!reserved_core_registers.IsEmpty()) {
643 blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true;
644 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000645 CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
646 reserved_fp_registers.Combine(CPURegList::GetCalleeSavedFP());
647 while (!reserved_core_registers.IsEmpty()) {
648 blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().code()] = true;
649 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100650}
651
652Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const {
653 if (type == Primitive::kPrimVoid) {
654 LOG(FATAL) << "Unreachable type " << type;
655 }
656
Alexandre Rames5319def2014-10-23 10:03:10 +0100657 if (IsFPType(type)) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000658 ssize_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfAllocatableFPRegisters);
659 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100660 return Location::FpuRegisterLocation(reg);
661 } else {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000662 ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfAllocatableRegisters);
663 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100664 return Location::RegisterLocation(reg);
665 }
666}
667
668void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
669 stream << Arm64ManagedRegister::FromXRegister(XRegister(reg));
670}
671
672void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
673 stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
674}
675
Alexandre Rames67555f72014-11-18 10:55:16 +0000676void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
677 if (constant->IsIntConstant() || constant->IsLongConstant()) {
678 __ Mov(Register(destination),
679 constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
680 : constant->AsLongConstant()->GetValue());
681 } else if (constant->IsFloatConstant()) {
682 __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
683 } else {
684 DCHECK(constant->IsDoubleConstant());
685 __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue());
686 }
687}
688
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000689void CodeGeneratorARM64::MoveHelper(Location destination,
690 Location source,
691 Primitive::Type type) {
692 if (source.Equals(destination)) {
693 return;
694 }
695 if (destination.IsRegister()) {
696 Register dst = RegisterFrom(destination, type);
697 if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
698 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
699 __ Ldr(dst, StackOperandFrom(source));
700 } else {
701 __ Mov(dst, OperandFrom(source, type));
702 }
703 } else if (destination.IsFpuRegister()) {
704 FPRegister dst = FPRegisterFrom(destination, type);
705 if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
706 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
707 __ Ldr(dst, StackOperandFrom(source));
708 } else if (source.IsFpuRegister()) {
709 __ Fmov(dst, FPRegisterFrom(source, type));
710 } else {
Alexandre Rames67555f72014-11-18 10:55:16 +0000711 MoveConstant(dst, source.GetConstant());
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000712 }
713 } else {
714 DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
715 if (source.IsRegister()) {
716 __ Str(RegisterFrom(source, type), StackOperandFrom(destination));
717 } else if (source.IsFpuRegister()) {
718 __ Str(FPRegisterFrom(source, type), StackOperandFrom(destination));
Alexandre Rames67555f72014-11-18 10:55:16 +0000719 } else if (source.IsConstant()) {
720 UseScratchRegisterScope temps(GetVIXLAssembler());
721 HConstant* cst = source.GetConstant();
722 CPURegister temp;
723 if (cst->IsIntConstant() || cst->IsLongConstant()) {
724 temp = cst->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
725 } else {
726 DCHECK(cst->IsFloatConstant() || cst->IsDoubleConstant());
727 temp = cst->IsFloatConstant() ? temps.AcquireS() : temps.AcquireD();
728 }
729 MoveConstant(temp, cst);
730 __ Str(temp, StackOperandFrom(destination));
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000731 } else {
Alexandre Rames67555f72014-11-18 10:55:16 +0000732 DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
733 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000734 Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW();
735 __ Ldr(temp, StackOperandFrom(source));
736 __ Str(temp, StackOperandFrom(destination));
737 }
738 }
739}
740
741void CodeGeneratorARM64::Load(Primitive::Type type,
Alexandre Rames67555f72014-11-18 10:55:16 +0000742 vixl::CPURegister dst,
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000743 const vixl::MemOperand& src) {
744 switch (type) {
745 case Primitive::kPrimBoolean:
Alexandre Rames67555f72014-11-18 10:55:16 +0000746 __ Ldrb(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000747 break;
748 case Primitive::kPrimByte:
Alexandre Rames67555f72014-11-18 10:55:16 +0000749 __ Ldrsb(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000750 break;
751 case Primitive::kPrimShort:
Alexandre Rames67555f72014-11-18 10:55:16 +0000752 __ Ldrsh(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000753 break;
754 case Primitive::kPrimChar:
Alexandre Rames67555f72014-11-18 10:55:16 +0000755 __ Ldrh(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000756 break;
757 case Primitive::kPrimInt:
758 case Primitive::kPrimNot:
759 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000760 case Primitive::kPrimFloat:
761 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +0000762 DCHECK(dst.Is64Bits() == Is64BitType(type));
763 __ Ldr(dst, src);
764 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000765 case Primitive::kPrimVoid:
766 LOG(FATAL) << "Unreachable type " << type;
767 }
768}
769
770void CodeGeneratorARM64::Store(Primitive::Type type,
Alexandre Rames67555f72014-11-18 10:55:16 +0000771 vixl::CPURegister rt,
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000772 const vixl::MemOperand& dst) {
773 switch (type) {
774 case Primitive::kPrimBoolean:
775 case Primitive::kPrimByte:
Alexandre Rames67555f72014-11-18 10:55:16 +0000776 __ Strb(Register(rt), dst);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000777 break;
778 case Primitive::kPrimChar:
779 case Primitive::kPrimShort:
Alexandre Rames67555f72014-11-18 10:55:16 +0000780 __ Strh(Register(rt), dst);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000781 break;
782 case Primitive::kPrimInt:
783 case Primitive::kPrimNot:
784 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000785 case Primitive::kPrimFloat:
786 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +0000787 DCHECK(rt.Is64Bits() == Is64BitType(type));
788 __ Str(rt, dst);
789 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000790 case Primitive::kPrimVoid:
791 LOG(FATAL) << "Unreachable type " << type;
792 }
793}
794
Alexandre Rames67555f72014-11-18 10:55:16 +0000795void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) {
796 DCHECK(current_method.IsW());
797 __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
798}
799
800void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
801 HInstruction* instruction,
802 uint32_t dex_pc) {
803 __ Ldr(lr, MemOperand(tr, entry_point_offset));
804 __ Blr(lr);
Serban Constantinescu02164b32014-11-13 14:05:07 +0000805 if (instruction != nullptr) {
806 RecordPcInfo(instruction, dex_pc);
807 DCHECK(instruction->IsSuspendCheck()
808 || instruction->IsBoundsCheck()
809 || instruction->IsNullCheck()
810 || instruction->IsDivZeroCheck()
811 || !IsLeafMethod());
812 }
Alexandre Rames67555f72014-11-18 10:55:16 +0000813}
814
815void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
816 vixl::Register class_reg) {
817 UseScratchRegisterScope temps(GetVIXLAssembler());
818 Register temp = temps.AcquireW();
819 __ Ldr(temp, HeapOperand(class_reg, mirror::Class::StatusOffset()));
820 __ Cmp(temp, mirror::Class::kStatusInitialized);
821 __ B(lt, slow_path->GetEntryLabel());
Serban Constantinescu02164b32014-11-13 14:05:07 +0000822 // Even if the initialized flag is set, we need to ensure consistent memory ordering.
823 __ Dmb(InnerShareable, BarrierReads);
Alexandre Rames67555f72014-11-18 10:55:16 +0000824 __ Bind(slow_path->GetExitLabel());
825}
Alexandre Rames5319def2014-10-23 10:03:10 +0100826
Serban Constantinescu02164b32014-11-13 14:05:07 +0000827void InstructionCodeGeneratorARM64::GenerateSuspendCheck(HSuspendCheck* instruction,
828 HBasicBlock* successor) {
829 SuspendCheckSlowPathARM64* slow_path =
830 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM64(instruction, successor);
831 codegen_->AddSlowPath(slow_path);
832 UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
833 Register temp = temps.AcquireW();
834
835 __ Ldrh(temp, MemOperand(tr, Thread::ThreadFlagsOffset<kArm64WordSize>().SizeValue()));
836 if (successor == nullptr) {
837 __ Cbnz(temp, slow_path->GetEntryLabel());
838 __ Bind(slow_path->GetReturnLabel());
839 } else {
840 __ Cbz(temp, codegen_->GetLabelOf(successor));
841 __ B(slow_path->GetEntryLabel());
842 // slow_path will return to GetLabelOf(successor).
843 }
844}
845
Alexandre Rames5319def2014-10-23 10:03:10 +0100846InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
847 CodeGeneratorARM64* codegen)
848 : HGraphVisitor(graph),
849 assembler_(codegen->GetAssembler()),
850 codegen_(codegen) {}
851
852#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100853 M(ParallelMove) \
Alexandre Rames5319def2014-10-23 10:03:10 +0100854
855#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
856
857enum UnimplementedInstructionBreakCode {
Alexandre Rames67555f72014-11-18 10:55:16 +0000858 // Using a base helps identify when we hit such breakpoints.
859 UnimplementedInstructionBreakCodeBaseCode = 0x900,
Alexandre Rames5319def2014-10-23 10:03:10 +0100860#define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name),
861 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION)
862#undef ENUM_UNIMPLEMENTED_INSTRUCTION
863};
864
865#define DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS(name) \
866 void InstructionCodeGeneratorARM64::Visit##name(H##name* instr) { \
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700867 UNUSED(instr); \
Alexandre Rames5319def2014-10-23 10:03:10 +0100868 __ Brk(UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name)); \
869 } \
870 void LocationsBuilderARM64::Visit##name(H##name* instr) { \
871 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); \
872 locations->SetOut(Location::Any()); \
873 }
874 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS)
875#undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS
876
877#undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE
Alexandre Rames67555f72014-11-18 10:55:16 +0000878#undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION
Alexandre Rames5319def2014-10-23 10:03:10 +0100879
Alexandre Rames67555f72014-11-18 10:55:16 +0000880void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100881 DCHECK_EQ(instr->InputCount(), 2U);
882 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
883 Primitive::Type type = instr->GetResultType();
884 switch (type) {
885 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000886 case Primitive::kPrimLong:
Alexandre Rames5319def2014-10-23 10:03:10 +0100887 locations->SetInAt(0, Location::RequiresRegister());
888 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +0000889 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +0100890 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000891
892 case Primitive::kPrimFloat:
893 case Primitive::kPrimDouble:
894 locations->SetInAt(0, Location::RequiresFpuRegister());
895 locations->SetInAt(1, Location::RequiresFpuRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +0000896 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +0100897 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000898
Alexandre Rames5319def2014-10-23 10:03:10 +0100899 default:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000900 LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +0100901 }
902}
903
Alexandre Rames67555f72014-11-18 10:55:16 +0000904void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100905 Primitive::Type type = instr->GetType();
Alexandre Rames5319def2014-10-23 10:03:10 +0100906
907 switch (type) {
908 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000909 case Primitive::kPrimLong: {
910 Register dst = OutputRegister(instr);
911 Register lhs = InputRegisterAt(instr, 0);
912 Operand rhs = InputOperandAt(instr, 1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100913 if (instr->IsAdd()) {
914 __ Add(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +0000915 } else if (instr->IsAnd()) {
916 __ And(dst, lhs, rhs);
917 } else if (instr->IsOr()) {
918 __ Orr(dst, lhs, rhs);
919 } else if (instr->IsSub()) {
Alexandre Rames5319def2014-10-23 10:03:10 +0100920 __ Sub(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +0000921 } else {
922 DCHECK(instr->IsXor());
923 __ Eor(dst, lhs, rhs);
Alexandre Rames5319def2014-10-23 10:03:10 +0100924 }
925 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000926 }
927 case Primitive::kPrimFloat:
928 case Primitive::kPrimDouble: {
929 FPRegister dst = OutputFPRegister(instr);
930 FPRegister lhs = InputFPRegisterAt(instr, 0);
931 FPRegister rhs = InputFPRegisterAt(instr, 1);
932 if (instr->IsAdd()) {
933 __ Fadd(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +0000934 } else if (instr->IsSub()) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000935 __ Fsub(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +0000936 } else {
937 LOG(FATAL) << "Unexpected floating-point binary operation";
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000938 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100939 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000940 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100941 default:
Alexandre Rames67555f72014-11-18 10:55:16 +0000942 LOG(FATAL) << "Unexpected binary operation type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +0100943 }
944}
945
Serban Constantinescu02164b32014-11-13 14:05:07 +0000946void LocationsBuilderARM64::HandleShift(HBinaryOperation* instr) {
947 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
948
949 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
950 Primitive::Type type = instr->GetResultType();
951 switch (type) {
952 case Primitive::kPrimInt:
953 case Primitive::kPrimLong: {
954 locations->SetInAt(0, Location::RequiresRegister());
955 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
956 locations->SetOut(Location::RequiresRegister());
957 break;
958 }
959 default:
960 LOG(FATAL) << "Unexpected shift type " << type;
961 }
962}
963
964void InstructionCodeGeneratorARM64::HandleShift(HBinaryOperation* instr) {
965 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
966
967 Primitive::Type type = instr->GetType();
968 switch (type) {
969 case Primitive::kPrimInt:
970 case Primitive::kPrimLong: {
971 Register dst = OutputRegister(instr);
972 Register lhs = InputRegisterAt(instr, 0);
973 Operand rhs = InputOperandAt(instr, 1);
974 if (rhs.IsImmediate()) {
975 uint32_t shift_value = (type == Primitive::kPrimInt)
976 ? static_cast<uint32_t>(rhs.immediate() & kMaxIntShiftValue)
977 : static_cast<uint32_t>(rhs.immediate() & kMaxLongShiftValue);
978 if (instr->IsShl()) {
979 __ Lsl(dst, lhs, shift_value);
980 } else if (instr->IsShr()) {
981 __ Asr(dst, lhs, shift_value);
982 } else {
983 __ Lsr(dst, lhs, shift_value);
984 }
985 } else {
986 Register rhs_reg = dst.IsX() ? rhs.reg().X() : rhs.reg().W();
987
988 if (instr->IsShl()) {
989 __ Lsl(dst, lhs, rhs_reg);
990 } else if (instr->IsShr()) {
991 __ Asr(dst, lhs, rhs_reg);
992 } else {
993 __ Lsr(dst, lhs, rhs_reg);
994 }
995 }
996 break;
997 }
998 default:
999 LOG(FATAL) << "Unexpected shift operation type " << type;
1000 }
1001}
1002
Alexandre Rames5319def2014-10-23 10:03:10 +01001003void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001004 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001005}
1006
1007void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001008 HandleBinaryOp(instruction);
1009}
1010
1011void LocationsBuilderARM64::VisitAnd(HAnd* instruction) {
1012 HandleBinaryOp(instruction);
1013}
1014
1015void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) {
1016 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001017}
1018
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001019void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
1020 LocationSummary* locations =
1021 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1022 locations->SetInAt(0, Location::RequiresRegister());
1023 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1024 locations->SetOut(Location::RequiresRegister());
1025}
1026
1027void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
1028 LocationSummary* locations = instruction->GetLocations();
1029 Primitive::Type type = instruction->GetType();
1030 Register obj = InputRegisterAt(instruction, 0);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001031 Location index = locations->InAt(1);
1032 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001033 MemOperand source = HeapOperand(obj);
Alexandre Rames67555f72014-11-18 10:55:16 +00001034 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001035
1036 if (index.IsConstant()) {
1037 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001038 source = HeapOperand(obj, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001039 } else {
1040 Register temp = temps.AcquireSameSizeAs(obj);
1041 Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
1042 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type)));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001043 source = HeapOperand(temp, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001044 }
1045
Alexandre Rames67555f72014-11-18 10:55:16 +00001046 codegen_->Load(type, OutputCPURegister(instruction), source);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001047}
1048
Alexandre Rames5319def2014-10-23 10:03:10 +01001049void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
1050 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1051 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001052 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001053}
1054
1055void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
1056 __ Ldr(OutputRegister(instruction),
1057 HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset()));
1058}
1059
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001060void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
1061 Primitive::Type value_type = instruction->GetComponentType();
1062 bool is_object = value_type == Primitive::kPrimNot;
1063 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1064 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1065 if (is_object) {
1066 InvokeRuntimeCallingConvention calling_convention;
1067 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
1068 locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
1069 locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
1070 } else {
1071 locations->SetInAt(0, Location::RequiresRegister());
1072 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1073 locations->SetInAt(2, Location::RequiresRegister());
1074 }
1075}
1076
1077void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
1078 Primitive::Type value_type = instruction->GetComponentType();
1079 if (value_type == Primitive::kPrimNot) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001080 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
1081
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001082 } else {
1083 LocationSummary* locations = instruction->GetLocations();
1084 Register obj = InputRegisterAt(instruction, 0);
Alexandre Rames67555f72014-11-18 10:55:16 +00001085 CPURegister value = InputCPURegisterAt(instruction, 2);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001086 Location index = locations->InAt(1);
1087 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001088 MemOperand destination = HeapOperand(obj);
Alexandre Rames67555f72014-11-18 10:55:16 +00001089 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001090
1091 if (index.IsConstant()) {
1092 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001093 destination = HeapOperand(obj, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001094 } else {
1095 Register temp = temps.AcquireSameSizeAs(obj);
1096 Register index_reg = InputRegisterAt(instruction, 1);
1097 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type)));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001098 destination = HeapOperand(temp, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001099 }
1100
1101 codegen_->Store(value_type, value, destination);
1102 }
1103}
1104
Alexandre Rames67555f72014-11-18 10:55:16 +00001105void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1106 LocationSummary* locations =
1107 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1108 locations->SetInAt(0, Location::RequiresRegister());
1109 locations->SetInAt(1, Location::RequiresRegister());
1110 if (instruction->HasUses()) {
1111 locations->SetOut(Location::SameAsFirstInput());
1112 }
1113}
1114
1115void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1116 BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64();
1117 codegen_->AddSlowPath(slow_path);
1118
1119 __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
1120 __ B(slow_path->GetEntryLabel(), hs);
1121}
1122
1123void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
1124 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1125 instruction, LocationSummary::kCallOnSlowPath);
1126 locations->SetInAt(0, Location::RequiresRegister());
1127 locations->SetInAt(1, Location::RequiresRegister());
1128}
1129
1130void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
1131 UseScratchRegisterScope temps(GetVIXLAssembler());
1132 Register obj = InputRegisterAt(instruction, 0);;
1133 Register cls = InputRegisterAt(instruction, 1);;
1134 Register temp = temps.AcquireW();
1135
1136 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64();
1137 codegen_->AddSlowPath(slow_path);
1138
1139 // TODO: avoid this check if we know obj is not null.
1140 __ Cbz(obj, slow_path->GetExitLabel());
1141 // Compare the class of `obj` with `cls`.
1142 __ Ldr(temp, HeapOperand(obj, mirror::Object::ClassOffset()));
1143 __ Cmp(temp, cls);
1144 __ B(ne, slow_path->GetEntryLabel());
1145 __ Bind(slow_path->GetExitLabel());
1146}
1147
1148void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) {
1149 LocationSummary* locations =
1150 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
1151 locations->SetInAt(0, Location::RequiresRegister());
1152 if (check->HasUses()) {
1153 locations->SetOut(Location::SameAsFirstInput());
1154 }
1155}
1156
1157void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) {
1158 // We assume the class is not null.
1159 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
1160 check->GetLoadClass(), check, check->GetDexPc(), true);
1161 codegen_->AddSlowPath(slow_path);
1162 GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
1163}
1164
Serban Constantinescu02164b32014-11-13 14:05:07 +00001165void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001166 LocationSummary* locations =
Serban Constantinescu02164b32014-11-13 14:05:07 +00001167 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
1168 Primitive::Type in_type = compare->InputAt(0)->GetType();
Alexandre Rames5319def2014-10-23 10:03:10 +01001169 switch (in_type) {
1170 case Primitive::kPrimLong: {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001171 locations->SetInAt(0, Location::RequiresRegister());
1172 locations->SetInAt(1, Location::RegisterOrConstant(compare->InputAt(1)));
1173 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1174 break;
1175 }
1176 case Primitive::kPrimFloat:
1177 case Primitive::kPrimDouble: {
1178 locations->SetInAt(0, Location::RequiresFpuRegister());
1179 locations->SetInAt(1, Location::RequiresFpuRegister());
1180 locations->SetOut(Location::RequiresRegister());
1181 break;
1182 }
1183 default:
1184 LOG(FATAL) << "Unexpected type for compare operation " << in_type;
1185 }
1186}
1187
1188void InstructionCodeGeneratorARM64::VisitCompare(HCompare* compare) {
1189 Primitive::Type in_type = compare->InputAt(0)->GetType();
1190
1191 // 0 if: left == right
1192 // 1 if: left > right
1193 // -1 if: left < right
1194 switch (in_type) {
1195 case Primitive::kPrimLong: {
1196 Register result = OutputRegister(compare);
1197 Register left = InputRegisterAt(compare, 0);
1198 Operand right = InputOperandAt(compare, 1);
1199
1200 __ Cmp(left, right);
1201 __ Cset(result, ne);
1202 __ Cneg(result, result, lt);
1203 break;
1204 }
1205 case Primitive::kPrimFloat:
1206 case Primitive::kPrimDouble: {
1207 Register result = OutputRegister(compare);
1208 FPRegister left = InputFPRegisterAt(compare, 0);
1209 FPRegister right = InputFPRegisterAt(compare, 1);
1210
1211 __ Fcmp(left, right);
1212 if (compare->IsGtBias()) {
1213 __ Cset(result, ne);
1214 } else {
1215 __ Csetm(result, ne);
1216 }
1217 __ Cneg(result, result, compare->IsGtBias() ? mi : gt);
Alexandre Rames5319def2014-10-23 10:03:10 +01001218 break;
1219 }
1220 default:
1221 LOG(FATAL) << "Unimplemented compare type " << in_type;
1222 }
1223}
1224
1225void LocationsBuilderARM64::VisitCondition(HCondition* instruction) {
1226 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1227 locations->SetInAt(0, Location::RequiresRegister());
1228 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1229 if (instruction->NeedsMaterialization()) {
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001230 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001231 }
1232}
1233
1234void InstructionCodeGeneratorARM64::VisitCondition(HCondition* instruction) {
1235 if (!instruction->NeedsMaterialization()) {
1236 return;
1237 }
1238
1239 LocationSummary* locations = instruction->GetLocations();
1240 Register lhs = InputRegisterAt(instruction, 0);
1241 Operand rhs = InputOperandAt(instruction, 1);
1242 Register res = RegisterFrom(locations->Out(), instruction->GetType());
1243 Condition cond = ARM64Condition(instruction->GetCondition());
1244
1245 __ Cmp(lhs, rhs);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001246 __ Cset(res, cond);
Alexandre Rames5319def2014-10-23 10:03:10 +01001247}
1248
1249#define FOR_EACH_CONDITION_INSTRUCTION(M) \
1250 M(Equal) \
1251 M(NotEqual) \
1252 M(LessThan) \
1253 M(LessThanOrEqual) \
1254 M(GreaterThan) \
1255 M(GreaterThanOrEqual)
1256#define DEFINE_CONDITION_VISITORS(Name) \
1257void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } \
1258void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }
1259FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
Alexandre Rames67555f72014-11-18 10:55:16 +00001260#undef DEFINE_CONDITION_VISITORS
Alexandre Rames5319def2014-10-23 10:03:10 +01001261#undef FOR_EACH_CONDITION_INSTRUCTION
1262
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001263void LocationsBuilderARM64::VisitDiv(HDiv* div) {
1264 LocationSummary* locations =
1265 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
1266 switch (div->GetResultType()) {
1267 case Primitive::kPrimInt:
1268 case Primitive::kPrimLong:
1269 locations->SetInAt(0, Location::RequiresRegister());
1270 locations->SetInAt(1, Location::RequiresRegister());
1271 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1272 break;
1273
1274 case Primitive::kPrimFloat:
1275 case Primitive::kPrimDouble:
1276 locations->SetInAt(0, Location::RequiresFpuRegister());
1277 locations->SetInAt(1, Location::RequiresFpuRegister());
1278 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1279 break;
1280
1281 default:
1282 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1283 }
1284}
1285
1286void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
1287 Primitive::Type type = div->GetResultType();
1288 switch (type) {
1289 case Primitive::kPrimInt:
1290 case Primitive::kPrimLong:
1291 __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
1292 break;
1293
1294 case Primitive::kPrimFloat:
1295 case Primitive::kPrimDouble:
1296 __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
1297 break;
1298
1299 default:
1300 LOG(FATAL) << "Unexpected div type " << type;
1301 }
1302}
1303
Alexandre Rames67555f72014-11-18 10:55:16 +00001304void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1305 LocationSummary* locations =
1306 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1307 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
1308 if (instruction->HasUses()) {
1309 locations->SetOut(Location::SameAsFirstInput());
1310 }
1311}
1312
1313void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1314 SlowPathCodeARM64* slow_path =
1315 new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction);
1316 codegen_->AddSlowPath(slow_path);
1317 Location value = instruction->GetLocations()->InAt(0);
1318
1319 if (value.IsConstant()) {
1320 int64_t divisor = Int64ConstantFrom(value);
1321 if (divisor == 0) {
1322 __ B(slow_path->GetEntryLabel());
1323 } else {
1324 LOG(FATAL) << "Divisions by non-null constants should have been optimized away.";
1325 }
1326 } else {
1327 __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
1328 }
1329}
1330
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001331void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1332 LocationSummary* locations =
1333 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1334 locations->SetOut(Location::ConstantLocation(constant));
1335}
1336
1337void InstructionCodeGeneratorARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1338 UNUSED(constant);
1339 // Will be generated at use site.
1340}
1341
Alexandre Rames5319def2014-10-23 10:03:10 +01001342void LocationsBuilderARM64::VisitExit(HExit* exit) {
1343 exit->SetLocations(nullptr);
1344}
1345
1346void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001347 UNUSED(exit);
Alexandre Rames5319def2014-10-23 10:03:10 +01001348 if (kIsDebugBuild) {
1349 down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable");
Alexandre Rames67555f72014-11-18 10:55:16 +00001350 __ Brk(__LINE__); // TODO: Introduce special markers for such code locations.
Alexandre Rames5319def2014-10-23 10:03:10 +01001351 }
1352}
1353
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001354void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) {
1355 LocationSummary* locations =
1356 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1357 locations->SetOut(Location::ConstantLocation(constant));
1358}
1359
1360void InstructionCodeGeneratorARM64::VisitFloatConstant(HFloatConstant* constant) {
1361 UNUSED(constant);
1362 // Will be generated at use site.
1363}
1364
Alexandre Rames5319def2014-10-23 10:03:10 +01001365void LocationsBuilderARM64::VisitGoto(HGoto* got) {
1366 got->SetLocations(nullptr);
1367}
1368
1369void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
1370 HBasicBlock* successor = got->GetSuccessor();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001371 DCHECK(!successor->IsExitBlock());
1372 HBasicBlock* block = got->GetBlock();
1373 HInstruction* previous = got->GetPrevious();
1374 HLoopInformation* info = block->GetLoopInformation();
1375
1376 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
1377 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1378 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1379 return;
1380 }
1381 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1382 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1383 }
1384 if (!codegen_->GoesToNextBlock(block, successor)) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001385 __ B(codegen_->GetLabelOf(successor));
1386 }
1387}
1388
1389void LocationsBuilderARM64::VisitIf(HIf* if_instr) {
1390 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1391 HInstruction* cond = if_instr->InputAt(0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001392 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001393 locations->SetInAt(0, Location::RequiresRegister());
1394 }
1395}
1396
1397void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) {
1398 HInstruction* cond = if_instr->InputAt(0);
Alexandre Rames5319def2014-10-23 10:03:10 +01001399 HCondition* condition = cond->AsCondition();
1400 vixl::Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1401 vixl::Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1402
Serban Constantinescu02164b32014-11-13 14:05:07 +00001403 if (cond->IsIntConstant()) {
1404 int32_t cond_value = cond->AsIntConstant()->GetValue();
1405 if (cond_value == 1) {
1406 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
1407 __ B(true_target);
1408 }
1409 return;
1410 } else {
1411 DCHECK_EQ(cond_value, 0);
1412 }
1413 } else if (!cond->IsCondition() || condition->NeedsMaterialization()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001414 // The condition instruction has been materialized, compare the output to 0.
1415 Location cond_val = if_instr->GetLocations()->InAt(0);
1416 DCHECK(cond_val.IsRegister());
1417 __ Cbnz(InputRegisterAt(if_instr, 0), true_target);
Alexandre Rames5319def2014-10-23 10:03:10 +01001418 } else {
1419 // The condition instruction has not been materialized, use its inputs as
1420 // the comparison and its condition as the branch condition.
1421 Register lhs = InputRegisterAt(condition, 0);
1422 Operand rhs = InputOperandAt(condition, 1);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001423 Condition arm64_cond = ARM64Condition(condition->GetCondition());
1424 if ((arm64_cond == eq || arm64_cond == ne) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
1425 if (arm64_cond == eq) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001426 __ Cbz(lhs, true_target);
1427 } else {
1428 __ Cbnz(lhs, true_target);
1429 }
1430 } else {
1431 __ Cmp(lhs, rhs);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001432 __ B(arm64_cond, true_target);
Alexandre Rames5319def2014-10-23 10:03:10 +01001433 }
1434 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001435 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
1436 __ B(false_target);
1437 }
1438}
1439
1440void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1441 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1442 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001443 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001444}
1445
1446void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001447 MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset());
Alexandre Rames67555f72014-11-18 10:55:16 +00001448 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
Alexandre Rames5319def2014-10-23 10:03:10 +01001449}
1450
1451void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1452 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1453 locations->SetInAt(0, Location::RequiresRegister());
1454 locations->SetInAt(1, Location::RequiresRegister());
1455}
1456
1457void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001458 Primitive::Type field_type = instruction->GetFieldType();
Alexandre Rames67555f72014-11-18 10:55:16 +00001459 CPURegister value = InputCPURegisterAt(instruction, 1);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001460 Register obj = InputRegisterAt(instruction, 0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001461 codegen_->Store(field_type, value, HeapOperand(obj, instruction->GetFieldOffset()));
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001462 if (field_type == Primitive::kPrimNot) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001463 codegen_->MarkGCCard(obj, Register(value));
Alexandre Rames5319def2014-10-23 10:03:10 +01001464 }
1465}
1466
Alexandre Rames67555f72014-11-18 10:55:16 +00001467void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
1468 LocationSummary::CallKind call_kind =
1469 instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
1470 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
1471 locations->SetInAt(0, Location::RequiresRegister());
1472 locations->SetInAt(1, Location::RequiresRegister());
1473 locations->SetOut(Location::RequiresRegister(), true); // The output does overlap inputs.
1474}
1475
1476void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
1477 LocationSummary* locations = instruction->GetLocations();
1478 Register obj = InputRegisterAt(instruction, 0);;
1479 Register cls = InputRegisterAt(instruction, 1);;
1480 Register out = OutputRegister(instruction);
1481
1482 vixl::Label done;
1483
1484 // Return 0 if `obj` is null.
1485 // TODO: Avoid this check if we know `obj` is not null.
1486 __ Mov(out, 0);
1487 __ Cbz(obj, &done);
1488
1489 // Compare the class of `obj` with `cls`.
Serban Constantinescu02164b32014-11-13 14:05:07 +00001490 __ Ldr(out, HeapOperand(obj, mirror::Object::ClassOffset()));
Alexandre Rames67555f72014-11-18 10:55:16 +00001491 __ Cmp(out, cls);
1492 if (instruction->IsClassFinal()) {
1493 // Classes must be equal for the instanceof to succeed.
1494 __ Cset(out, eq);
1495 } else {
1496 // If the classes are not equal, we go into a slow path.
1497 DCHECK(locations->OnlyCallsOnSlowPath());
1498 SlowPathCodeARM64* slow_path =
1499 new (GetGraph()->GetArena()) TypeCheckSlowPathARM64();
1500 codegen_->AddSlowPath(slow_path);
1501 __ B(ne, slow_path->GetEntryLabel());
1502 __ Mov(out, 1);
1503 __ Bind(slow_path->GetExitLabel());
1504 }
1505
1506 __ Bind(&done);
1507}
1508
Alexandre Rames5319def2014-10-23 10:03:10 +01001509void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
1510 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1511 locations->SetOut(Location::ConstantLocation(constant));
1512}
1513
1514void InstructionCodeGeneratorARM64::VisitIntConstant(HIntConstant* constant) {
1515 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001516 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001517}
1518
Alexandre Rames5319def2014-10-23 10:03:10 +01001519void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
1520 LocationSummary* locations =
1521 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
1522 locations->AddTemp(LocationFrom(x0));
1523
1524 InvokeDexCallingConventionVisitor calling_convention_visitor;
1525 for (size_t i = 0; i < invoke->InputCount(); i++) {
1526 HInstruction* input = invoke->InputAt(i);
1527 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1528 }
1529
1530 Primitive::Type return_type = invoke->GetType();
1531 if (return_type != Primitive::kPrimVoid) {
1532 locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type));
1533 }
1534}
1535
Alexandre Rames67555f72014-11-18 10:55:16 +00001536void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1537 HandleInvoke(invoke);
1538}
1539
1540void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1541 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1542 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1543 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1544 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1545 Location receiver = invoke->GetLocations()->InAt(0);
1546 Offset class_offset = mirror::Object::ClassOffset();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001547 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
Alexandre Rames67555f72014-11-18 10:55:16 +00001548
1549 // The register ip1 is required to be used for the hidden argument in
1550 // art_quick_imt_conflict_trampoline, so prevent VIXL from using it.
1551 UseScratchRegisterScope scratch_scope(GetVIXLAssembler());
1552 scratch_scope.Exclude(ip1);
1553 __ Mov(ip1, invoke->GetDexMethodIndex());
1554
1555 // temp = object->GetClass();
1556 if (receiver.IsStackSlot()) {
1557 __ Ldr(temp, StackOperandFrom(receiver));
1558 __ Ldr(temp, HeapOperand(temp, class_offset));
1559 } else {
1560 __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
1561 }
1562 // temp = temp->GetImtEntryAt(method_offset);
1563 __ Ldr(temp, HeapOperand(temp, method_offset));
1564 // lr = temp->GetEntryPoint();
1565 __ Ldr(lr, HeapOperand(temp, entry_point));
1566 // lr();
1567 __ Blr(lr);
1568 DCHECK(!codegen_->IsLeafMethod());
1569 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1570}
1571
1572void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1573 HandleInvoke(invoke);
1574}
1575
1576void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
1577 HandleInvoke(invoke);
1578}
1579
Alexandre Rames5319def2014-10-23 10:03:10 +01001580void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
1581 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1582 // Make sure that ArtMethod* is passed in W0 as per the calling convention
1583 DCHECK(temp.Is(w0));
1584 size_t index_in_cache = mirror::Array::DataOffset(kHeapRefSize).SizeValue() +
1585 invoke->GetIndexInDexCache() * kHeapRefSize;
1586
1587 // TODO: Implement all kinds of calls:
1588 // 1) boot -> boot
1589 // 2) app -> boot
1590 // 3) app -> app
1591 //
1592 // Currently we implement the app -> app logic, which looks up in the resolve cache.
1593
1594 // temp = method;
Alexandre Rames67555f72014-11-18 10:55:16 +00001595 codegen_->LoadCurrentMethod(temp);
Alexandre Rames5319def2014-10-23 10:03:10 +01001596 // temp = temp->dex_cache_resolved_methods_;
Serban Constantinescu02164b32014-11-13 14:05:07 +00001597 __ Ldr(temp, HeapOperand(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset()));
Alexandre Rames5319def2014-10-23 10:03:10 +01001598 // temp = temp[index_in_cache];
Serban Constantinescu02164b32014-11-13 14:05:07 +00001599 __ Ldr(temp, HeapOperand(temp, index_in_cache));
Alexandre Rames5319def2014-10-23 10:03:10 +01001600 // lr = temp->entry_point_from_quick_compiled_code_;
Serban Constantinescu02164b32014-11-13 14:05:07 +00001601 __ Ldr(lr, HeapOperand(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
1602 kArm64WordSize)));
Alexandre Rames5319def2014-10-23 10:03:10 +01001603 // lr();
1604 __ Blr(lr);
1605
1606 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1607 DCHECK(!codegen_->IsLeafMethod());
1608}
1609
1610void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1611 LocationSummary* locations = invoke->GetLocations();
1612 Location receiver = locations->InAt(0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001613 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
Alexandre Rames5319def2014-10-23 10:03:10 +01001614 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1615 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1616 Offset class_offset = mirror::Object::ClassOffset();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001617 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
Alexandre Rames5319def2014-10-23 10:03:10 +01001618
1619 // temp = object->GetClass();
1620 if (receiver.IsStackSlot()) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001621 __ Ldr(temp, MemOperand(sp, receiver.GetStackIndex()));
1622 __ Ldr(temp, HeapOperand(temp, class_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001623 } else {
1624 DCHECK(receiver.IsRegister());
Serban Constantinescu02164b32014-11-13 14:05:07 +00001625 __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001626 }
1627 // temp = temp->GetMethodAt(method_offset);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001628 __ Ldr(temp, HeapOperand(temp, method_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001629 // lr = temp->GetEntryPoint();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001630 __ Ldr(lr, HeapOperand(temp, entry_point.SizeValue()));
Alexandre Rames5319def2014-10-23 10:03:10 +01001631 // lr();
1632 __ Blr(lr);
1633 DCHECK(!codegen_->IsLeafMethod());
1634 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1635}
1636
Alexandre Rames67555f72014-11-18 10:55:16 +00001637void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
1638 LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
1639 : LocationSummary::kNoCall;
1640 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
1641 locations->SetOut(Location::RequiresRegister());
1642}
1643
1644void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
1645 Register out = OutputRegister(cls);
1646 if (cls->IsReferrersClass()) {
1647 DCHECK(!cls->CanCallRuntime());
1648 DCHECK(!cls->MustGenerateClinitCheck());
1649 codegen_->LoadCurrentMethod(out);
1650 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
1651 } else {
1652 DCHECK(cls->CanCallRuntime());
1653 codegen_->LoadCurrentMethod(out);
1654 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset()));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001655 __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Alexandre Rames67555f72014-11-18 10:55:16 +00001656
1657 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
1658 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
1659 codegen_->AddSlowPath(slow_path);
1660 __ Cbz(out, slow_path->GetEntryLabel());
1661 if (cls->MustGenerateClinitCheck()) {
1662 GenerateClassInitializationCheck(slow_path, out);
1663 } else {
1664 __ Bind(slow_path->GetExitLabel());
1665 }
1666 }
1667}
1668
1669void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
1670 LocationSummary* locations =
1671 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
1672 locations->SetOut(Location::RequiresRegister());
1673}
1674
1675void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
1676 MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
1677 __ Ldr(OutputRegister(instruction), exception);
1678 __ Str(wzr, exception);
1679}
1680
Alexandre Rames5319def2014-10-23 10:03:10 +01001681void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
1682 load->SetLocations(nullptr);
1683}
1684
1685void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) {
1686 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001687 UNUSED(load);
Alexandre Rames5319def2014-10-23 10:03:10 +01001688}
1689
Alexandre Rames67555f72014-11-18 10:55:16 +00001690void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
1691 LocationSummary* locations =
1692 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
1693 locations->SetOut(Location::RequiresRegister());
1694}
1695
1696void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
1697 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
1698 codegen_->AddSlowPath(slow_path);
1699
1700 Register out = OutputRegister(load);
1701 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08001702 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
1703 __ Ldr(out, HeapOperand(out, mirror::Class::DexCacheStringsOffset()));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001704 __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Alexandre Rames67555f72014-11-18 10:55:16 +00001705 __ Cbz(out, slow_path->GetEntryLabel());
1706 __ Bind(slow_path->GetExitLabel());
1707}
1708
Alexandre Rames5319def2014-10-23 10:03:10 +01001709void LocationsBuilderARM64::VisitLocal(HLocal* local) {
1710 local->SetLocations(nullptr);
1711}
1712
1713void InstructionCodeGeneratorARM64::VisitLocal(HLocal* local) {
1714 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1715}
1716
1717void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
1718 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1719 locations->SetOut(Location::ConstantLocation(constant));
1720}
1721
1722void InstructionCodeGeneratorARM64::VisitLongConstant(HLongConstant* constant) {
1723 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001724 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001725}
1726
Alexandre Rames67555f72014-11-18 10:55:16 +00001727void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
1728 LocationSummary* locations =
1729 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1730 InvokeRuntimeCallingConvention calling_convention;
1731 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
1732}
1733
1734void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
1735 codegen_->InvokeRuntime(instruction->IsEnter()
1736 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
1737 instruction,
1738 instruction->GetDexPc());
1739}
1740
Alexandre Rames42d641b2014-10-27 14:00:51 +00001741void LocationsBuilderARM64::VisitMul(HMul* mul) {
1742 LocationSummary* locations =
1743 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1744 switch (mul->GetResultType()) {
1745 case Primitive::kPrimInt:
1746 case Primitive::kPrimLong:
1747 locations->SetInAt(0, Location::RequiresRegister());
1748 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001749 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00001750 break;
1751
1752 case Primitive::kPrimFloat:
1753 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001754 locations->SetInAt(0, Location::RequiresFpuRegister());
1755 locations->SetInAt(1, Location::RequiresFpuRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00001756 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00001757 break;
1758
1759 default:
1760 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1761 }
1762}
1763
1764void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) {
1765 switch (mul->GetResultType()) {
1766 case Primitive::kPrimInt:
1767 case Primitive::kPrimLong:
1768 __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
1769 break;
1770
1771 case Primitive::kPrimFloat:
1772 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001773 __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1));
Alexandre Rames42d641b2014-10-27 14:00:51 +00001774 break;
1775
1776 default:
1777 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1778 }
1779}
1780
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001781void LocationsBuilderARM64::VisitNeg(HNeg* neg) {
1782 LocationSummary* locations =
1783 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1784 switch (neg->GetResultType()) {
1785 case Primitive::kPrimInt:
Alexandre Rames67555f72014-11-18 10:55:16 +00001786 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001787 locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0)));
Alexandre Rames67555f72014-11-18 10:55:16 +00001788 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001789 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001790
1791 case Primitive::kPrimFloat:
1792 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +00001793 locations->SetInAt(0, Location::RequiresFpuRegister());
1794 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001795 break;
1796
1797 default:
1798 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1799 }
1800}
1801
1802void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
1803 switch (neg->GetResultType()) {
1804 case Primitive::kPrimInt:
1805 case Primitive::kPrimLong:
1806 __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
1807 break;
1808
1809 case Primitive::kPrimFloat:
1810 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +00001811 __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001812 break;
1813
1814 default:
1815 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1816 }
1817}
1818
1819void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) {
1820 LocationSummary* locations =
1821 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1822 InvokeRuntimeCallingConvention calling_convention;
1823 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
1824 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
1825 locations->SetOut(LocationFrom(x0));
1826 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(2)));
1827}
1828
1829void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
1830 LocationSummary* locations = instruction->GetLocations();
1831 InvokeRuntimeCallingConvention calling_convention;
1832 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
1833 DCHECK(type_index.Is(w0));
1834 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
1835 DCHECK(current_method.Is(w1));
Alexandre Rames67555f72014-11-18 10:55:16 +00001836 codegen_->LoadCurrentMethod(current_method);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001837 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +00001838 codegen_->InvokeRuntime(
1839 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001840}
1841
Alexandre Rames5319def2014-10-23 10:03:10 +01001842void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
1843 LocationSummary* locations =
1844 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1845 InvokeRuntimeCallingConvention calling_convention;
1846 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
1847 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
1848 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
1849}
1850
1851void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) {
1852 LocationSummary* locations = instruction->GetLocations();
1853 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
1854 DCHECK(type_index.Is(w0));
1855 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
1856 DCHECK(current_method.Is(w1));
Alexandre Rames67555f72014-11-18 10:55:16 +00001857 codegen_->LoadCurrentMethod(current_method);
Alexandre Rames5319def2014-10-23 10:03:10 +01001858 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +00001859 codegen_->InvokeRuntime(
1860 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
Alexandre Rames5319def2014-10-23 10:03:10 +01001861}
1862
1863void LocationsBuilderARM64::VisitNot(HNot* instruction) {
1864 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Alexandre Rames4e596512014-11-07 15:56:50 +00001865 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001866 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001867}
1868
1869void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
1870 switch (instruction->InputAt(0)->GetType()) {
1871 case Primitive::kPrimBoolean:
1872 __ Eor(OutputRegister(instruction), InputRegisterAt(instruction, 0), Operand(1));
1873 break;
1874
1875 case Primitive::kPrimInt:
Alexandre Rames5319def2014-10-23 10:03:10 +01001876 case Primitive::kPrimLong:
Roland Levillain55dcfb52014-10-24 18:09:09 +01001877 __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
Alexandre Rames5319def2014-10-23 10:03:10 +01001878 break;
1879
1880 default:
1881 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
1882 }
1883}
1884
1885void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
1886 LocationSummary* locations =
1887 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1888 locations->SetInAt(0, Location::RequiresRegister());
1889 if (instruction->HasUses()) {
1890 locations->SetOut(Location::SameAsFirstInput());
1891 }
1892}
1893
1894void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
1895 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction);
1896 codegen_->AddSlowPath(slow_path);
1897
1898 LocationSummary* locations = instruction->GetLocations();
1899 Location obj = locations->InAt(0);
1900 if (obj.IsRegister()) {
1901 __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel());
1902 } else {
1903 DCHECK(obj.IsConstant()) << obj;
1904 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1905 __ B(slow_path->GetEntryLabel());
1906 }
1907}
1908
Alexandre Rames67555f72014-11-18 10:55:16 +00001909void LocationsBuilderARM64::VisitOr(HOr* instruction) {
1910 HandleBinaryOp(instruction);
1911}
1912
1913void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) {
1914 HandleBinaryOp(instruction);
1915}
1916
Alexandre Rames5319def2014-10-23 10:03:10 +01001917void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
1918 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1919 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1920 if (location.IsStackSlot()) {
1921 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1922 } else if (location.IsDoubleStackSlot()) {
1923 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1924 }
1925 locations->SetOut(location);
1926}
1927
1928void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) {
1929 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001930 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001931}
1932
1933void LocationsBuilderARM64::VisitPhi(HPhi* instruction) {
1934 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1935 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1936 locations->SetInAt(i, Location::Any());
1937 }
1938 locations->SetOut(Location::Any());
1939}
1940
1941void InstructionCodeGeneratorARM64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001942 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001943 LOG(FATAL) << "Unreachable";
1944}
1945
Serban Constantinescu02164b32014-11-13 14:05:07 +00001946void LocationsBuilderARM64::VisitRem(HRem* rem) {
1947 LocationSummary* locations =
1948 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
1949 switch (rem->GetResultType()) {
1950 case Primitive::kPrimInt:
1951 case Primitive::kPrimLong:
1952 locations->SetInAt(0, Location::RequiresRegister());
1953 locations->SetInAt(1, Location::RequiresRegister());
1954 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1955 break;
1956
1957 default:
1958 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType();
1959 }
1960}
1961
1962void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) {
1963 Primitive::Type type = rem->GetResultType();
1964 switch (type) {
1965 case Primitive::kPrimInt:
1966 case Primitive::kPrimLong: {
1967 UseScratchRegisterScope temps(GetVIXLAssembler());
1968 Register dividend = InputRegisterAt(rem, 0);
1969 Register divisor = InputRegisterAt(rem, 1);
1970 Register output = OutputRegister(rem);
1971 Register temp = temps.AcquireSameSizeAs(output);
1972
1973 __ Sdiv(temp, dividend, divisor);
1974 __ Msub(output, temp, divisor, dividend);
1975 break;
1976 }
1977
1978 default:
1979 LOG(FATAL) << "Unexpected rem type " << type;
1980 }
1981}
1982
Alexandre Rames5319def2014-10-23 10:03:10 +01001983void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
1984 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1985 Primitive::Type return_type = instruction->InputAt(0)->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001986 locations->SetInAt(0, ARM64ReturnLocation(return_type));
Alexandre Rames5319def2014-10-23 10:03:10 +01001987}
1988
1989void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001990 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001991 codegen_->GenerateFrameExit();
1992 __ Br(lr);
1993}
1994
1995void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) {
1996 instruction->SetLocations(nullptr);
1997}
1998
1999void InstructionCodeGeneratorARM64::VisitReturnVoid(HReturnVoid* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002000 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002001 codegen_->GenerateFrameExit();
2002 __ Br(lr);
2003}
2004
Serban Constantinescu02164b32014-11-13 14:05:07 +00002005void LocationsBuilderARM64::VisitShl(HShl* shl) {
2006 HandleShift(shl);
2007}
2008
2009void InstructionCodeGeneratorARM64::VisitShl(HShl* shl) {
2010 HandleShift(shl);
2011}
2012
2013void LocationsBuilderARM64::VisitShr(HShr* shr) {
2014 HandleShift(shr);
2015}
2016
2017void InstructionCodeGeneratorARM64::VisitShr(HShr* shr) {
2018 HandleShift(shr);
2019}
2020
Alexandre Rames5319def2014-10-23 10:03:10 +01002021void LocationsBuilderARM64::VisitStoreLocal(HStoreLocal* store) {
2022 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
2023 Primitive::Type field_type = store->InputAt(1)->GetType();
2024 switch (field_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002025 case Primitive::kPrimNot:
Alexandre Rames5319def2014-10-23 10:03:10 +01002026 case Primitive::kPrimBoolean:
2027 case Primitive::kPrimByte:
2028 case Primitive::kPrimChar:
2029 case Primitive::kPrimShort:
2030 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002031 case Primitive::kPrimFloat:
Alexandre Rames5319def2014-10-23 10:03:10 +01002032 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
2033 break;
2034
2035 case Primitive::kPrimLong:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002036 case Primitive::kPrimDouble:
Alexandre Rames5319def2014-10-23 10:03:10 +01002037 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
2038 break;
2039
2040 default:
2041 LOG(FATAL) << "Unimplemented local type " << field_type;
2042 }
2043}
2044
2045void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002046 UNUSED(store);
Alexandre Rames5319def2014-10-23 10:03:10 +01002047}
2048
2049void LocationsBuilderARM64::VisitSub(HSub* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002050 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002051}
2052
2053void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002054 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002055}
2056
Alexandre Rames67555f72014-11-18 10:55:16 +00002057void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2058 LocationSummary* locations =
2059 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2060 locations->SetInAt(0, Location::RequiresRegister());
2061 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2062}
2063
2064void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002065 MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset());
2066 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
Alexandre Rames67555f72014-11-18 10:55:16 +00002067}
2068
2069void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Alexandre Rames5319def2014-10-23 10:03:10 +01002070 LocationSummary* locations =
2071 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2072 locations->SetInAt(0, Location::RequiresRegister());
2073 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Rames5319def2014-10-23 10:03:10 +01002074}
2075
Alexandre Rames67555f72014-11-18 10:55:16 +00002076void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2077 CPURegister value = InputCPURegisterAt(instruction, 1);
2078 Register cls = InputRegisterAt(instruction, 0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00002079 Offset offset = instruction->GetFieldOffset();
Alexandre Rames67555f72014-11-18 10:55:16 +00002080 Primitive::Type field_type = instruction->GetFieldType();
Alexandre Rames5319def2014-10-23 10:03:10 +01002081
Serban Constantinescu02164b32014-11-13 14:05:07 +00002082 codegen_->Store(field_type, value, HeapOperand(cls, offset));
Alexandre Rames67555f72014-11-18 10:55:16 +00002083 if (field_type == Primitive::kPrimNot) {
2084 codegen_->MarkGCCard(cls, Register(value));
2085 }
Alexandre Rames5319def2014-10-23 10:03:10 +01002086}
2087
2088void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
2089 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
2090}
2091
2092void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002093 HBasicBlock* block = instruction->GetBlock();
2094 if (block->GetLoopInformation() != nullptr) {
2095 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
2096 // The back edge will generate the suspend check.
2097 return;
2098 }
2099 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
2100 // The goto will generate the suspend check.
2101 return;
2102 }
2103 GenerateSuspendCheck(instruction, nullptr);
Alexandre Rames5319def2014-10-23 10:03:10 +01002104}
2105
2106void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
2107 temp->SetLocations(nullptr);
2108}
2109
2110void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) {
2111 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002112 UNUSED(temp);
Alexandre Rames5319def2014-10-23 10:03:10 +01002113}
2114
Alexandre Rames67555f72014-11-18 10:55:16 +00002115void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
2116 LocationSummary* locations =
2117 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2118 InvokeRuntimeCallingConvention calling_convention;
2119 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2120}
2121
2122void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
2123 codegen_->InvokeRuntime(
2124 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
2125}
2126
2127void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
2128 LocationSummary* locations =
2129 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
2130 Primitive::Type input_type = conversion->GetInputType();
2131 Primitive::Type result_type = conversion->GetResultType();
2132 if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
2133 (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
2134 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
2135 }
2136
2137 if (IsFPType(input_type)) {
2138 locations->SetInAt(0, Location::RequiresFpuRegister());
2139 } else {
2140 locations->SetInAt(0, Location::RequiresRegister());
2141 }
2142
2143 if (IsFPType(result_type)) {
2144 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2145 } else {
2146 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2147 }
2148}
2149
2150void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
2151 Primitive::Type result_type = conversion->GetResultType();
2152 Primitive::Type input_type = conversion->GetInputType();
2153
2154 DCHECK_NE(input_type, result_type);
2155
2156 if (IsIntegralType(result_type) && IsIntegralType(input_type)) {
2157 int result_size = Primitive::ComponentSize(result_type);
2158 int input_size = Primitive::ComponentSize(input_type);
2159 int min_size = kBitsPerByte * std::min(result_size, input_size);
Serban Constantinescu02164b32014-11-13 14:05:07 +00002160 Register output = OutputRegister(conversion);
2161 Register source = InputRegisterAt(conversion, 0);
Alexandre Rames67555f72014-11-18 10:55:16 +00002162 if ((result_type == Primitive::kPrimChar) ||
2163 ((input_type == Primitive::kPrimChar) && (result_size > input_size))) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002164 __ Ubfx(output, output.IsX() ? source.X() : source.W(), 0, min_size);
Alexandre Rames67555f72014-11-18 10:55:16 +00002165 } else {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002166 __ Sbfx(output, output.IsX() ? source.X() : source.W(), 0, min_size);
Alexandre Rames67555f72014-11-18 10:55:16 +00002167 }
Serban Constantinescu02164b32014-11-13 14:05:07 +00002168 } else if (IsFPType(result_type) && IsIntegralType(input_type)) {
2169 CHECK(input_type == Primitive::kPrimInt || input_type == Primitive::kPrimLong);
2170 __ Scvtf(OutputFPRegister(conversion), InputRegisterAt(conversion, 0));
2171 } else if (IsIntegralType(result_type) && IsFPType(input_type)) {
2172 CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
2173 __ Fcvtzs(OutputRegister(conversion), InputFPRegisterAt(conversion, 0));
2174 } else if (IsFPType(result_type) && IsFPType(input_type)) {
2175 __ Fcvt(OutputFPRegister(conversion), InputFPRegisterAt(conversion, 0));
2176 } else {
2177 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
2178 << " to " << result_type;
Alexandre Rames67555f72014-11-18 10:55:16 +00002179 }
Serban Constantinescu02164b32014-11-13 14:05:07 +00002180}
Alexandre Rames67555f72014-11-18 10:55:16 +00002181
Serban Constantinescu02164b32014-11-13 14:05:07 +00002182void LocationsBuilderARM64::VisitUShr(HUShr* ushr) {
2183 HandleShift(ushr);
2184}
2185
2186void InstructionCodeGeneratorARM64::VisitUShr(HUShr* ushr) {
2187 HandleShift(ushr);
Alexandre Rames67555f72014-11-18 10:55:16 +00002188}
2189
2190void LocationsBuilderARM64::VisitXor(HXor* instruction) {
2191 HandleBinaryOp(instruction);
2192}
2193
2194void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) {
2195 HandleBinaryOp(instruction);
2196}
2197
2198#undef __
2199#undef QUICK_ENTRY_POINT
2200
Alexandre Rames5319def2014-10-23 10:03:10 +01002201} // namespace arm64
2202} // namespace art