blob: 543288296882c15cd81b93d09a80c9886c3ed80c [file] [log] [blame]
Alexandre Rames5319def2014-10-23 10:03:10 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_arm64.h"
18
19#include "entrypoints/quick/quick_entrypoints.h"
20#include "gc/accounting/card_table.h"
21#include "mirror/array-inl.h"
22#include "mirror/art_method.h"
23#include "mirror/class.h"
24#include "thread.h"
25#include "utils/arm64/assembler_arm64.h"
26#include "utils/assembler.h"
27#include "utils/stack_checks.h"
28
29
30using namespace vixl; // NOLINT(build/namespaces)
31
32#ifdef __
33#error "ARM64 Codegen VIXL macro-assembler macro already defined."
34#endif
35
36
37namespace art {
38
39namespace arm64 {
40
Alexandre Rames5319def2014-10-23 10:03:10 +010041// TODO: clean-up some of the constant definitions.
42static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>);
43static constexpr int kCurrentMethodStackOffset = 0;
44
45namespace {
Alexandre Ramesa89086e2014-11-07 17:13:25 +000046
47bool IsFPType(Primitive::Type type) {
48 return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble;
49}
50
51bool Is64BitType(Primitive::Type type) {
52 return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
53}
54
Alexandre Rames5319def2014-10-23 10:03:10 +010055// Convenience helpers to ease conversion to and from VIXL operands.
56
57int VIXLRegCodeFromART(int code) {
58 // TODO: static check?
59 DCHECK_EQ(SP, 31);
60 DCHECK_EQ(WSP, 31);
61 DCHECK_EQ(XZR, 32);
62 DCHECK_EQ(WZR, 32);
63 if (code == SP) {
64 return vixl::kSPRegInternalCode;
65 }
66 if (code == XZR) {
67 return vixl::kZeroRegCode;
68 }
69 return code;
70}
71
72int ARTRegCodeFromVIXL(int code) {
73 // TODO: static check?
74 DCHECK_EQ(SP, 31);
75 DCHECK_EQ(WSP, 31);
76 DCHECK_EQ(XZR, 32);
77 DCHECK_EQ(WZR, 32);
78 if (code == vixl::kSPRegInternalCode) {
79 return SP;
80 }
81 if (code == vixl::kZeroRegCode) {
82 return XZR;
83 }
84 return code;
85}
86
87Register XRegisterFrom(Location location) {
88 return Register::XRegFromCode(VIXLRegCodeFromART(location.reg()));
89}
90
91Register WRegisterFrom(Location location) {
92 return Register::WRegFromCode(VIXLRegCodeFromART(location.reg()));
93}
94
95Register RegisterFrom(Location location, Primitive::Type type) {
96 DCHECK(type != Primitive::kPrimVoid && !IsFPType(type));
97 return type == Primitive::kPrimLong ? XRegisterFrom(location) : WRegisterFrom(location);
98}
99
100Register OutputRegister(HInstruction* instr) {
101 return RegisterFrom(instr->GetLocations()->Out(), instr->GetType());
102}
103
104Register InputRegisterAt(HInstruction* instr, int input_index) {
105 return RegisterFrom(instr->GetLocations()->InAt(input_index),
106 instr->InputAt(input_index)->GetType());
107}
108
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000109FPRegister DRegisterFrom(Location location) {
110 return FPRegister::DRegFromCode(location.reg());
111}
112
113FPRegister SRegisterFrom(Location location) {
114 return FPRegister::SRegFromCode(location.reg());
115}
116
117FPRegister FPRegisterFrom(Location location, Primitive::Type type) {
118 DCHECK(IsFPType(type));
119 return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location);
120}
121
122FPRegister OutputFPRegister(HInstruction* instr) {
123 return FPRegisterFrom(instr->GetLocations()->Out(), instr->GetType());
124}
125
126FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) {
127 return FPRegisterFrom(instr->GetLocations()->InAt(input_index),
128 instr->InputAt(input_index)->GetType());
129}
130
Alexandre Rames5319def2014-10-23 10:03:10 +0100131int64_t Int64ConstantFrom(Location location) {
132 HConstant* instr = location.GetConstant();
133 return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue()
134 : instr->AsLongConstant()->GetValue();
135}
136
137Operand OperandFrom(Location location, Primitive::Type type) {
138 if (location.IsRegister()) {
139 return Operand(RegisterFrom(location, type));
140 } else {
141 return Operand(Int64ConstantFrom(location));
142 }
143}
144
145Operand InputOperandAt(HInstruction* instr, int input_index) {
146 return OperandFrom(instr->GetLocations()->InAt(input_index),
147 instr->InputAt(input_index)->GetType());
148}
149
150MemOperand StackOperandFrom(Location location) {
151 return MemOperand(sp, location.GetStackIndex());
152}
153
154MemOperand HeapOperand(const Register& base, Offset offset) {
155 // A heap reference must be 32bit, so fit in a W register.
156 DCHECK(base.IsW());
157 return MemOperand(base.X(), offset.SizeValue());
158}
159
160MemOperand HeapOperandFrom(Location location, Primitive::Type type, Offset offset) {
161 return HeapOperand(RegisterFrom(location, type), offset);
162}
163
164Location LocationFrom(const Register& reg) {
165 return Location::RegisterLocation(ARTRegCodeFromVIXL(reg.code()));
166}
167
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000168Location LocationFrom(const FPRegister& fpreg) {
169 return Location::FpuRegisterLocation(fpreg.code());
170}
171
Alexandre Rames5319def2014-10-23 10:03:10 +0100172} // namespace
173
174inline Condition ARM64Condition(IfCondition cond) {
175 switch (cond) {
176 case kCondEQ: return eq;
177 case kCondNE: return ne;
178 case kCondLT: return lt;
179 case kCondLE: return le;
180 case kCondGT: return gt;
181 case kCondGE: return ge;
182 default:
183 LOG(FATAL) << "Unknown if condition";
184 }
185 return nv; // Unreachable.
186}
187
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000188Location ARM64ReturnLocation(Primitive::Type return_type) {
189 DCHECK_NE(return_type, Primitive::kPrimVoid);
190 // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the
191 // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`,
192 // but we use the exact registers for clarity.
193 if (return_type == Primitive::kPrimFloat) {
194 return LocationFrom(s0);
195 } else if (return_type == Primitive::kPrimDouble) {
196 return LocationFrom(d0);
197 } else if (return_type == Primitive::kPrimLong) {
198 return LocationFrom(x0);
199 } else {
200 return LocationFrom(w0);
201 }
202}
203
Alexandre Rames5319def2014-10-23 10:03:10 +0100204static const Register kRuntimeParameterCoreRegisters[] = { x0, x1, x2, x3, x4, x5, x6, x7 };
205static constexpr size_t kRuntimeParameterCoreRegistersLength =
206 arraysize(kRuntimeParameterCoreRegisters);
207static const FPRegister kRuntimeParameterFpuRegisters[] = { };
208static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
209
210class InvokeRuntimeCallingConvention : public CallingConvention<Register, FPRegister> {
211 public:
212 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
213
214 InvokeRuntimeCallingConvention()
215 : CallingConvention(kRuntimeParameterCoreRegisters,
216 kRuntimeParameterCoreRegistersLength,
217 kRuntimeParameterFpuRegisters,
218 kRuntimeParameterFpuRegistersLength) {}
219
220 Location GetReturnLocation(Primitive::Type return_type);
221
222 private:
223 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
224};
225
226Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type return_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000227 return ARM64ReturnLocation(return_type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100228}
229
230#define __ reinterpret_cast<Arm64Assembler*>(codegen->GetAssembler())->vixl_masm_->
231
232class SlowPathCodeARM64 : public SlowPathCode {
233 public:
234 SlowPathCodeARM64() : entry_label_(), exit_label_() {}
235
236 vixl::Label* GetEntryLabel() { return &entry_label_; }
237 vixl::Label* GetExitLabel() { return &exit_label_; }
238
239 private:
240 vixl::Label entry_label_;
241 vixl::Label exit_label_;
242
243 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM64);
244};
245
246class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
247 public:
248 explicit BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
249 Location index_location,
250 Location length_location)
251 : instruction_(instruction),
252 index_location_(index_location),
253 length_location_(length_location) {}
254
255 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
256 CodeGeneratorARM64* arm64_codegen = reinterpret_cast<CodeGeneratorARM64*>(codegen);
257 __ Bind(GetEntryLabel());
258 InvokeRuntimeCallingConvention calling_convention;
259 arm64_codegen->MoveHelper(LocationFrom(calling_convention.GetRegisterAt(0)),
260 index_location_, Primitive::kPrimInt);
261 arm64_codegen->MoveHelper(LocationFrom(calling_convention.GetRegisterAt(1)),
262 length_location_, Primitive::kPrimInt);
263 size_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pThrowArrayBounds).SizeValue();
264 __ Ldr(lr, MemOperand(tr, offset));
265 __ Blr(lr);
266 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
267 }
268
269 private:
270 HBoundsCheck* const instruction_;
271 const Location index_location_;
272 const Location length_location_;
273
274 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
275};
276
277class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
278 public:
279 explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {}
280
281 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
282 __ Bind(GetEntryLabel());
283 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pThrowNullPointer).Int32Value();
284 __ Ldr(lr, MemOperand(tr, offset));
285 __ Blr(lr);
286 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
287 }
288
289 private:
290 HNullCheck* const instruction_;
291
292 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM64);
293};
294
295class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 {
296 public:
297 explicit SuspendCheckSlowPathARM64(HSuspendCheck* instruction,
298 HBasicBlock* successor)
299 : instruction_(instruction), successor_(successor) {}
300
301 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
302 size_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pTestSuspend).SizeValue();
303 __ Bind(GetEntryLabel());
304 __ Ldr(lr, MemOperand(tr, offset));
305 __ Blr(lr);
306 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
307 __ B(GetReturnLabel());
308 }
309
310 vixl::Label* GetReturnLabel() {
311 DCHECK(successor_ == nullptr);
312 return &return_label_;
313 }
314
315
316 private:
317 HSuspendCheck* const instruction_;
318 // If not null, the block to branch to after the suspend check.
319 HBasicBlock* const successor_;
320
321 // If `successor_` is null, the label to branch to after the suspend check.
322 vixl::Label return_label_;
323
324 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
325};
326
327#undef __
328
329Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
330 Location next_location;
331 if (type == Primitive::kPrimVoid) {
332 LOG(FATAL) << "Unreachable type " << type;
333 }
334
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000335 if (IsFPType(type) && (fp_index_ < calling_convention.GetNumberOfFpuRegisters())) {
336 next_location = LocationFrom(calling_convention.GetFpuRegisterAt(fp_index_++));
337 } else if (!IsFPType(type) && (gp_index_ < calling_convention.GetNumberOfRegisters())) {
338 next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++));
339 } else {
340 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
341 next_location = Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
342 : Location::StackSlot(stack_offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100343 }
344
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000345 // Space on the stack is reserved for all arguments.
346 stack_index_ += Is64BitType(type) ? 2 : 1;
Alexandre Rames5319def2014-10-23 10:03:10 +0100347 return next_location;
348}
349
350CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph)
351 : CodeGenerator(graph,
352 kNumberOfAllocatableRegisters,
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000353 kNumberOfAllocatableFPRegisters,
Alexandre Rames5319def2014-10-23 10:03:10 +0100354 kNumberOfAllocatableRegisterPairs),
355 block_labels_(nullptr),
356 location_builder_(graph, this),
357 instruction_visitor_(graph, this) {}
358
359#define __ reinterpret_cast<Arm64Assembler*>(GetAssembler())->vixl_masm_->
360
361void CodeGeneratorARM64::GenerateFrameEntry() {
362 // TODO: Add proper support for the stack overflow check.
363 UseScratchRegisterScope temps(assembler_.vixl_masm_);
364 Register temp = temps.AcquireX();
365 __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
366 __ Ldr(temp, MemOperand(temp, 0));
367 RecordPcInfo(nullptr, 0);
368
369 CPURegList preserved_regs = GetFramePreservedRegisters();
370 int frame_size = GetFrameSize();
371 core_spill_mask_ |= preserved_regs.list();
372
373 __ Str(w0, MemOperand(sp, -frame_size, PreIndex));
374 __ PokeCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
375
376 // Stack layout:
377 // sp[frame_size - 8] : lr.
378 // ... : other preserved registers.
379 // sp[frame_size - regs_size]: first preserved register.
380 // ... : reserved frame space.
381 // sp[0] : context pointer.
382}
383
384void CodeGeneratorARM64::GenerateFrameExit() {
385 int frame_size = GetFrameSize();
386 CPURegList preserved_regs = GetFramePreservedRegisters();
387 __ PeekCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
388 __ Drop(frame_size);
389}
390
391void CodeGeneratorARM64::Bind(HBasicBlock* block) {
392 __ Bind(GetLabelOf(block));
393}
394
Alexandre Rames5319def2014-10-23 10:03:10 +0100395void CodeGeneratorARM64::Move(HInstruction* instruction,
396 Location location,
397 HInstruction* move_for) {
398 LocationSummary* locations = instruction->GetLocations();
399 if (locations != nullptr && locations->Out().Equals(location)) {
400 return;
401 }
402
403 Primitive::Type type = instruction->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000404 DCHECK_NE(type, Primitive::kPrimVoid);
Alexandre Rames5319def2014-10-23 10:03:10 +0100405
406 if (instruction->IsIntConstant() || instruction->IsLongConstant()) {
407 int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue()
408 : instruction->AsLongConstant()->GetValue();
409 if (location.IsRegister()) {
410 Register dst = RegisterFrom(location, type);
411 DCHECK((instruction->IsIntConstant() && dst.Is32Bits()) ||
412 (instruction->IsLongConstant() && dst.Is64Bits()));
413 __ Mov(dst, value);
414 } else {
415 DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
416 UseScratchRegisterScope temps(assembler_.vixl_masm_);
417 Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
418 __ Mov(temp, value);
419 __ Str(temp, StackOperandFrom(location));
420 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000421 } else if (instruction->IsTemporary()) {
422 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
423 MoveHelper(location, temp_location, type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100424 } else if (instruction->IsLoadLocal()) {
425 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000426 if (Is64BitType(type)) {
427 MoveHelper(location, Location::DoubleStackSlot(stack_slot), type);
428 } else {
429 MoveHelper(location, Location::StackSlot(stack_slot), type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100430 }
431
432 } else {
433 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
434 MoveHelper(location, locations->Out(), type);
435 }
436}
437
438size_t CodeGeneratorARM64::FrameEntrySpillSize() const {
439 return GetFramePreservedRegistersSize();
440}
441
442Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const {
443 Primitive::Type type = load->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000444
Alexandre Rames5319def2014-10-23 10:03:10 +0100445 switch (type) {
446 case Primitive::kPrimNot:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000447 case Primitive::kPrimInt:
448 case Primitive::kPrimFloat:
449 return Location::StackSlot(GetStackSlot(load->GetLocal()));
450
451 case Primitive::kPrimLong:
452 case Primitive::kPrimDouble:
453 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
454
Alexandre Rames5319def2014-10-23 10:03:10 +0100455 case Primitive::kPrimBoolean:
456 case Primitive::kPrimByte:
457 case Primitive::kPrimChar:
458 case Primitive::kPrimShort:
Alexandre Rames5319def2014-10-23 10:03:10 +0100459 case Primitive::kPrimVoid:
Alexandre Rames5319def2014-10-23 10:03:10 +0100460 LOG(FATAL) << "Unexpected type " << type;
461 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000462
Alexandre Rames5319def2014-10-23 10:03:10 +0100463 LOG(FATAL) << "Unreachable";
464 return Location::NoLocation();
465}
466
467void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
468 UseScratchRegisterScope temps(assembler_.vixl_masm_);
469 Register card = temps.AcquireX();
470 Register temp = temps.AcquireX();
471 vixl::Label done;
472 __ Cbz(value, &done);
473 __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
474 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
475 __ Strb(card, MemOperand(card, temp));
476 __ Bind(&done);
477}
478
479void CodeGeneratorARM64::SetupBlockedRegisters() const {
480 // Block reserved registers:
481 // ip0 (VIXL temporary)
482 // ip1 (VIXL temporary)
483 // xSuspend (Suspend counter)
484 // lr
485 // sp is not part of the allocatable registers, so we don't need to block it.
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000486 // TODO: Avoid blocking callee-saved registers, and instead preserve them
487 // where necessary.
Alexandre Rames5319def2014-10-23 10:03:10 +0100488 CPURegList reserved_core_registers = vixl_reserved_core_registers;
489 reserved_core_registers.Combine(runtime_reserved_core_registers);
Alexandre Rames5319def2014-10-23 10:03:10 +0100490 reserved_core_registers.Combine(quick_callee_saved_registers);
491 while (!reserved_core_registers.IsEmpty()) {
492 blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true;
493 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000494 CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
495 reserved_fp_registers.Combine(CPURegList::GetCalleeSavedFP());
496 while (!reserved_core_registers.IsEmpty()) {
497 blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().code()] = true;
498 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100499}
500
501Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const {
502 if (type == Primitive::kPrimVoid) {
503 LOG(FATAL) << "Unreachable type " << type;
504 }
505
Alexandre Rames5319def2014-10-23 10:03:10 +0100506 if (IsFPType(type)) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000507 ssize_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfAllocatableFPRegisters);
508 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100509 return Location::FpuRegisterLocation(reg);
510 } else {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000511 ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfAllocatableRegisters);
512 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100513 return Location::RegisterLocation(reg);
514 }
515}
516
517void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
518 stream << Arm64ManagedRegister::FromXRegister(XRegister(reg));
519}
520
521void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
522 stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
523}
524
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000525void CodeGeneratorARM64::MoveHelper(Location destination,
526 Location source,
527 Primitive::Type type) {
528 if (source.Equals(destination)) {
529 return;
530 }
531 if (destination.IsRegister()) {
532 Register dst = RegisterFrom(destination, type);
533 if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
534 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
535 __ Ldr(dst, StackOperandFrom(source));
536 } else {
537 __ Mov(dst, OperandFrom(source, type));
538 }
539 } else if (destination.IsFpuRegister()) {
540 FPRegister dst = FPRegisterFrom(destination, type);
541 if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
542 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
543 __ Ldr(dst, StackOperandFrom(source));
544 } else if (source.IsFpuRegister()) {
545 __ Fmov(dst, FPRegisterFrom(source, type));
546 } else {
547 HConstant* cst = source.GetConstant();
548 if (cst->IsFloatConstant()) {
549 __ Fmov(dst, cst->AsFloatConstant()->GetValue());
550 } else {
551 DCHECK(cst->IsDoubleConstant());
552 __ Fmov(dst, cst->AsDoubleConstant()->GetValue());
553 }
554 }
555 } else {
556 DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
557 if (source.IsRegister()) {
558 __ Str(RegisterFrom(source, type), StackOperandFrom(destination));
559 } else if (source.IsFpuRegister()) {
560 __ Str(FPRegisterFrom(source, type), StackOperandFrom(destination));
561 } else {
562 UseScratchRegisterScope temps(assembler_.vixl_masm_);
563 Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW();
564 __ Ldr(temp, StackOperandFrom(source));
565 __ Str(temp, StackOperandFrom(destination));
566 }
567 }
568}
569
570void CodeGeneratorARM64::Load(Primitive::Type type,
571 vixl::Register dst,
572 const vixl::MemOperand& src) {
573 switch (type) {
574 case Primitive::kPrimBoolean:
575 __ Ldrb(dst, src);
576 break;
577 case Primitive::kPrimByte:
578 __ Ldrsb(dst, src);
579 break;
580 case Primitive::kPrimShort:
581 __ Ldrsh(dst, src);
582 break;
583 case Primitive::kPrimChar:
584 __ Ldrh(dst, src);
585 break;
586 case Primitive::kPrimInt:
587 case Primitive::kPrimNot:
588 case Primitive::kPrimLong:
589 DCHECK(dst.Is64Bits() == (type == Primitive::kPrimLong));
590 __ Ldr(dst, src);
591 break;
592 case Primitive::kPrimFloat:
593 case Primitive::kPrimDouble:
594 case Primitive::kPrimVoid:
595 LOG(FATAL) << "Unreachable type " << type;
596 }
597}
598
599void CodeGeneratorARM64::Store(Primitive::Type type,
600 vixl::Register rt,
601 const vixl::MemOperand& dst) {
602 switch (type) {
603 case Primitive::kPrimBoolean:
604 case Primitive::kPrimByte:
605 __ Strb(rt, dst);
606 break;
607 case Primitive::kPrimChar:
608 case Primitive::kPrimShort:
609 __ Strh(rt, dst);
610 break;
611 case Primitive::kPrimInt:
612 case Primitive::kPrimNot:
613 case Primitive::kPrimLong:
614 DCHECK(rt.Is64Bits() == (type == Primitive::kPrimLong));
615 __ Str(rt, dst);
616 break;
617 case Primitive::kPrimFloat:
618 case Primitive::kPrimDouble:
619 case Primitive::kPrimVoid:
620 LOG(FATAL) << "Unreachable type " << type;
621 }
622}
623
Alexandre Rames5319def2014-10-23 10:03:10 +0100624#undef __
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000625#define __ GetAssembler()->vixl_masm_->
Alexandre Rames5319def2014-10-23 10:03:10 +0100626
627InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
628 CodeGeneratorARM64* codegen)
629 : HGraphVisitor(graph),
630 assembler_(codegen->GetAssembler()),
631 codegen_(codegen) {}
632
633#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +0000634 M(And) \
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000635 M(CheckCast) \
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100636 M(ClinitCheck) \
Calin Juravled0d48522014-11-04 16:40:20 +0000637 M(DivZeroCheck) \
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000638 M(InstanceOf) \
Nicolas Geoffray52839d12014-11-07 17:47:25 +0000639 M(InvokeInterface) \
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100640 M(LoadClass) \
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +0000641 M(LoadException) \
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000642 M(LoadString) \
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +0000643 M(MonitorOperation) \
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +0000644 M(Or) \
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100645 M(ParallelMove) \
Calin Juravlebacfec32014-11-14 15:54:36 +0000646 M(Rem) \
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100647 M(StaticFieldGet) \
648 M(StaticFieldSet) \
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +0000649 M(Throw) \
Roland Levillaindff1f282014-11-05 14:15:05 +0000650 M(TypeConversion) \
Calin Juravlebacfec32014-11-14 15:54:36 +0000651 M(Xor) \
Alexandre Rames5319def2014-10-23 10:03:10 +0100652
653#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
654
655enum UnimplementedInstructionBreakCode {
656#define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name),
657 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION)
658#undef ENUM_UNIMPLEMENTED_INSTRUCTION
659};
660
661#define DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS(name) \
662 void InstructionCodeGeneratorARM64::Visit##name(H##name* instr) { \
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700663 UNUSED(instr); \
Alexandre Rames5319def2014-10-23 10:03:10 +0100664 __ Brk(UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name)); \
665 } \
666 void LocationsBuilderARM64::Visit##name(H##name* instr) { \
667 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); \
668 locations->SetOut(Location::Any()); \
669 }
670 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS)
671#undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS
672
673#undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE
674
675void LocationsBuilderARM64::HandleAddSub(HBinaryOperation* instr) {
676 DCHECK(instr->IsAdd() || instr->IsSub());
677 DCHECK_EQ(instr->InputCount(), 2U);
678 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
679 Primitive::Type type = instr->GetResultType();
680 switch (type) {
681 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000682 case Primitive::kPrimLong:
Alexandre Rames5319def2014-10-23 10:03:10 +0100683 locations->SetInAt(0, Location::RequiresRegister());
684 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +0000685 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +0100686 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000687
688 case Primitive::kPrimFloat:
689 case Primitive::kPrimDouble:
690 locations->SetInAt(0, Location::RequiresFpuRegister());
691 locations->SetInAt(1, Location::RequiresFpuRegister());
692 locations->SetOut(Location::RequiresFpuRegister());
Alexandre Rames5319def2014-10-23 10:03:10 +0100693 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000694
Alexandre Rames5319def2014-10-23 10:03:10 +0100695 default:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000696 LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +0100697 }
698}
699
700void InstructionCodeGeneratorARM64::HandleAddSub(HBinaryOperation* instr) {
701 DCHECK(instr->IsAdd() || instr->IsSub());
702
703 Primitive::Type type = instr->GetType();
Alexandre Rames5319def2014-10-23 10:03:10 +0100704
705 switch (type) {
706 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000707 case Primitive::kPrimLong: {
708 Register dst = OutputRegister(instr);
709 Register lhs = InputRegisterAt(instr, 0);
710 Operand rhs = InputOperandAt(instr, 1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100711 if (instr->IsAdd()) {
712 __ Add(dst, lhs, rhs);
713 } else {
714 __ Sub(dst, lhs, rhs);
715 }
716 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000717 }
718 case Primitive::kPrimFloat:
719 case Primitive::kPrimDouble: {
720 FPRegister dst = OutputFPRegister(instr);
721 FPRegister lhs = InputFPRegisterAt(instr, 0);
722 FPRegister rhs = InputFPRegisterAt(instr, 1);
723 if (instr->IsAdd()) {
724 __ Fadd(dst, lhs, rhs);
725 } else {
726 __ Fsub(dst, lhs, rhs);
727 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100728 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000729 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100730 default:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000731 LOG(FATAL) << "Unexpected add/sub type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +0100732 }
733}
734
735void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
736 HandleAddSub(instruction);
737}
738
739void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
740 HandleAddSub(instruction);
741}
742
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000743void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
744 LocationSummary* locations =
745 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
746 locations->SetInAt(0, Location::RequiresRegister());
747 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
748 locations->SetOut(Location::RequiresRegister());
749}
750
751void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
752 LocationSummary* locations = instruction->GetLocations();
753 Primitive::Type type = instruction->GetType();
754 Register obj = InputRegisterAt(instruction, 0);
755 Register out = OutputRegister(instruction);
756 Location index = locations->InAt(1);
757 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value();
758 MemOperand source(obj);
759 UseScratchRegisterScope temps(GetAssembler()->vixl_masm_);
760
761 if (index.IsConstant()) {
762 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
763 source = MemOperand(obj, offset);
764 } else {
765 Register temp = temps.AcquireSameSizeAs(obj);
766 Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
767 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type)));
768 source = MemOperand(temp, offset);
769 }
770
771 codegen_->Load(type, out, source);
772}
773
Alexandre Rames5319def2014-10-23 10:03:10 +0100774void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
775 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
776 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +0000777 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +0100778}
779
780void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
781 __ Ldr(OutputRegister(instruction),
782 HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset()));
783}
784
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000785void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
786 Primitive::Type value_type = instruction->GetComponentType();
787 bool is_object = value_type == Primitive::kPrimNot;
788 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
789 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
790 if (is_object) {
791 InvokeRuntimeCallingConvention calling_convention;
792 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
793 locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
794 locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
795 } else {
796 locations->SetInAt(0, Location::RequiresRegister());
797 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
798 locations->SetInAt(2, Location::RequiresRegister());
799 }
800}
801
802void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
803 Primitive::Type value_type = instruction->GetComponentType();
804 if (value_type == Primitive::kPrimNot) {
805 __ Ldr(lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAputObject).Int32Value()));
806 __ Blr(lr);
807 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
808 DCHECK(!codegen_->IsLeafMethod());
809 } else {
810 LocationSummary* locations = instruction->GetLocations();
811 Register obj = InputRegisterAt(instruction, 0);
812 Register value = InputRegisterAt(instruction, 2);
813 Location index = locations->InAt(1);
814 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
815 MemOperand destination(obj);
816 UseScratchRegisterScope temps(GetAssembler()->vixl_masm_);
817
818 if (index.IsConstant()) {
819 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
820 destination = MemOperand(obj, offset);
821 } else {
822 Register temp = temps.AcquireSameSizeAs(obj);
823 Register index_reg = InputRegisterAt(instruction, 1);
824 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type)));
825 destination = MemOperand(temp, offset);
826 }
827
828 codegen_->Store(value_type, value, destination);
829 }
830}
831
Alexandre Rames5319def2014-10-23 10:03:10 +0100832void LocationsBuilderARM64::VisitCompare(HCompare* instruction) {
833 LocationSummary* locations =
834 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
835 locations->SetInAt(0, Location::RequiresRegister());
836 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +0000837 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +0100838}
839
840void InstructionCodeGeneratorARM64::VisitCompare(HCompare* instruction) {
841 Primitive::Type in_type = instruction->InputAt(0)->GetType();
842
843 DCHECK_EQ(in_type, Primitive::kPrimLong);
844 switch (in_type) {
845 case Primitive::kPrimLong: {
846 vixl::Label done;
847 Register result = OutputRegister(instruction);
848 Register left = InputRegisterAt(instruction, 0);
849 Operand right = InputOperandAt(instruction, 1);
850 __ Subs(result, left, right);
851 __ B(eq, &done);
852 __ Mov(result, 1);
853 __ Cneg(result, result, le);
854 __ Bind(&done);
855 break;
856 }
857 default:
858 LOG(FATAL) << "Unimplemented compare type " << in_type;
859 }
860}
861
862void LocationsBuilderARM64::VisitCondition(HCondition* instruction) {
863 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
864 locations->SetInAt(0, Location::RequiresRegister());
865 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
866 if (instruction->NeedsMaterialization()) {
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +0000867 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +0100868 }
869}
870
871void InstructionCodeGeneratorARM64::VisitCondition(HCondition* instruction) {
872 if (!instruction->NeedsMaterialization()) {
873 return;
874 }
875
876 LocationSummary* locations = instruction->GetLocations();
877 Register lhs = InputRegisterAt(instruction, 0);
878 Operand rhs = InputOperandAt(instruction, 1);
879 Register res = RegisterFrom(locations->Out(), instruction->GetType());
880 Condition cond = ARM64Condition(instruction->GetCondition());
881
882 __ Cmp(lhs, rhs);
883 __ Csel(res, vixl::Assembler::AppropriateZeroRegFor(res), Operand(1), InvertCondition(cond));
884}
885
886#define FOR_EACH_CONDITION_INSTRUCTION(M) \
887 M(Equal) \
888 M(NotEqual) \
889 M(LessThan) \
890 M(LessThanOrEqual) \
891 M(GreaterThan) \
892 M(GreaterThanOrEqual)
893#define DEFINE_CONDITION_VISITORS(Name) \
894void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } \
895void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }
896FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
897#undef FOR_EACH_CONDITION_INSTRUCTION
898
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000899void LocationsBuilderARM64::VisitDiv(HDiv* div) {
900 LocationSummary* locations =
901 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
902 switch (div->GetResultType()) {
903 case Primitive::kPrimInt:
904 case Primitive::kPrimLong:
905 locations->SetInAt(0, Location::RequiresRegister());
906 locations->SetInAt(1, Location::RequiresRegister());
907 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
908 break;
909
910 case Primitive::kPrimFloat:
911 case Primitive::kPrimDouble:
912 locations->SetInAt(0, Location::RequiresFpuRegister());
913 locations->SetInAt(1, Location::RequiresFpuRegister());
914 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
915 break;
916
917 default:
918 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
919 }
920}
921
922void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
923 Primitive::Type type = div->GetResultType();
924 switch (type) {
925 case Primitive::kPrimInt:
926 case Primitive::kPrimLong:
927 __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
928 break;
929
930 case Primitive::kPrimFloat:
931 case Primitive::kPrimDouble:
932 __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
933 break;
934
935 default:
936 LOG(FATAL) << "Unexpected div type " << type;
937 }
938}
939
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000940void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
941 LocationSummary* locations =
942 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
943 locations->SetOut(Location::ConstantLocation(constant));
944}
945
946void InstructionCodeGeneratorARM64::VisitDoubleConstant(HDoubleConstant* constant) {
947 UNUSED(constant);
948 // Will be generated at use site.
949}
950
Alexandre Rames5319def2014-10-23 10:03:10 +0100951void LocationsBuilderARM64::VisitExit(HExit* exit) {
952 exit->SetLocations(nullptr);
953}
954
955void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700956 UNUSED(exit);
Alexandre Rames5319def2014-10-23 10:03:10 +0100957 if (kIsDebugBuild) {
958 down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable");
959 __ Brk(0); // TODO: Introduce special markers for such code locations.
960 }
961}
962
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000963void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) {
964 LocationSummary* locations =
965 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
966 locations->SetOut(Location::ConstantLocation(constant));
967}
968
969void InstructionCodeGeneratorARM64::VisitFloatConstant(HFloatConstant* constant) {
970 UNUSED(constant);
971 // Will be generated at use site.
972}
973
Alexandre Rames5319def2014-10-23 10:03:10 +0100974void LocationsBuilderARM64::VisitGoto(HGoto* got) {
975 got->SetLocations(nullptr);
976}
977
978void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
979 HBasicBlock* successor = got->GetSuccessor();
980 // TODO: Support for suspend checks emission.
981 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
982 __ B(codegen_->GetLabelOf(successor));
983 }
984}
985
986void LocationsBuilderARM64::VisitIf(HIf* if_instr) {
987 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
988 HInstruction* cond = if_instr->InputAt(0);
989 DCHECK(cond->IsCondition());
990 if (cond->AsCondition()->NeedsMaterialization()) {
991 locations->SetInAt(0, Location::RequiresRegister());
992 }
993}
994
995void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) {
996 HInstruction* cond = if_instr->InputAt(0);
997 DCHECK(cond->IsCondition());
998 HCondition* condition = cond->AsCondition();
999 vixl::Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1000 vixl::Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1001
1002 // TODO: Support constant condition input in VisitIf.
1003
1004 if (condition->NeedsMaterialization()) {
1005 // The condition instruction has been materialized, compare the output to 0.
1006 Location cond_val = if_instr->GetLocations()->InAt(0);
1007 DCHECK(cond_val.IsRegister());
1008 __ Cbnz(InputRegisterAt(if_instr, 0), true_target);
1009
1010 } else {
1011 // The condition instruction has not been materialized, use its inputs as
1012 // the comparison and its condition as the branch condition.
1013 Register lhs = InputRegisterAt(condition, 0);
1014 Operand rhs = InputOperandAt(condition, 1);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001015 Condition arm64_cond = ARM64Condition(condition->GetCondition());
1016 if ((arm64_cond == eq || arm64_cond == ne) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
1017 if (arm64_cond == eq) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001018 __ Cbz(lhs, true_target);
1019 } else {
1020 __ Cbnz(lhs, true_target);
1021 }
1022 } else {
1023 __ Cmp(lhs, rhs);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001024 __ B(arm64_cond, true_target);
Alexandre Rames5319def2014-10-23 10:03:10 +01001025 }
1026 }
1027
1028 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
1029 __ B(false_target);
1030 }
1031}
1032
1033void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1034 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1035 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001036 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001037}
1038
1039void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001040 MemOperand field = MemOperand(InputRegisterAt(instruction, 0),
1041 instruction->GetFieldOffset().Uint32Value());
1042 codegen_->Load(instruction->GetType(), OutputRegister(instruction), field);
Alexandre Rames5319def2014-10-23 10:03:10 +01001043}
1044
1045void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1046 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1047 locations->SetInAt(0, Location::RequiresRegister());
1048 locations->SetInAt(1, Location::RequiresRegister());
1049}
1050
1051void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001052 Primitive::Type field_type = instruction->GetFieldType();
Alexandre Rames5319def2014-10-23 10:03:10 +01001053 Register value = InputRegisterAt(instruction, 1);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001054 Register obj = InputRegisterAt(instruction, 0);
1055 codegen_->Store(field_type, value, MemOperand(obj, instruction->GetFieldOffset().Uint32Value()));
1056 if (field_type == Primitive::kPrimNot) {
1057 codegen_->MarkGCCard(obj, value);
Alexandre Rames5319def2014-10-23 10:03:10 +01001058 }
1059}
1060
1061void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
1062 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1063 locations->SetOut(Location::ConstantLocation(constant));
1064}
1065
1066void InstructionCodeGeneratorARM64::VisitIntConstant(HIntConstant* constant) {
1067 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001068 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001069}
1070
1071void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
1072 HandleInvoke(invoke);
1073}
1074
1075void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1076 HandleInvoke(invoke);
1077}
1078
1079void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
1080 LocationSummary* locations =
1081 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
1082 locations->AddTemp(LocationFrom(x0));
1083
1084 InvokeDexCallingConventionVisitor calling_convention_visitor;
1085 for (size_t i = 0; i < invoke->InputCount(); i++) {
1086 HInstruction* input = invoke->InputAt(i);
1087 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1088 }
1089
1090 Primitive::Type return_type = invoke->GetType();
1091 if (return_type != Primitive::kPrimVoid) {
1092 locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type));
1093 }
1094}
1095
1096void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
1097 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1098 // Make sure that ArtMethod* is passed in W0 as per the calling convention
1099 DCHECK(temp.Is(w0));
1100 size_t index_in_cache = mirror::Array::DataOffset(kHeapRefSize).SizeValue() +
1101 invoke->GetIndexInDexCache() * kHeapRefSize;
1102
1103 // TODO: Implement all kinds of calls:
1104 // 1) boot -> boot
1105 // 2) app -> boot
1106 // 3) app -> app
1107 //
1108 // Currently we implement the app -> app logic, which looks up in the resolve cache.
1109
1110 // temp = method;
1111 __ Ldr(temp, MemOperand(sp, kCurrentMethodStackOffset));
1112 // temp = temp->dex_cache_resolved_methods_;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001113 __ Ldr(temp, MemOperand(temp.X(),
1114 mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
Alexandre Rames5319def2014-10-23 10:03:10 +01001115 // temp = temp[index_in_cache];
1116 __ Ldr(temp, MemOperand(temp.X(), index_in_cache));
1117 // lr = temp->entry_point_from_quick_compiled_code_;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001118 __ Ldr(lr, MemOperand(temp.X(),
1119 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
Alexandre Rames5319def2014-10-23 10:03:10 +01001120 // lr();
1121 __ Blr(lr);
1122
1123 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1124 DCHECK(!codegen_->IsLeafMethod());
1125}
1126
1127void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1128 LocationSummary* locations = invoke->GetLocations();
1129 Location receiver = locations->InAt(0);
1130 Register temp = XRegisterFrom(invoke->GetLocations()->GetTemp(0));
1131 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1132 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1133 Offset class_offset = mirror::Object::ClassOffset();
1134 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset();
1135
1136 // temp = object->GetClass();
1137 if (receiver.IsStackSlot()) {
1138 __ Ldr(temp.W(), MemOperand(sp, receiver.GetStackIndex()));
1139 __ Ldr(temp.W(), MemOperand(temp, class_offset.SizeValue()));
1140 } else {
1141 DCHECK(receiver.IsRegister());
1142 __ Ldr(temp.W(), HeapOperandFrom(receiver, Primitive::kPrimNot,
1143 class_offset));
1144 }
1145 // temp = temp->GetMethodAt(method_offset);
1146 __ Ldr(temp.W(), MemOperand(temp, method_offset));
1147 // lr = temp->GetEntryPoint();
1148 __ Ldr(lr, MemOperand(temp, entry_point.SizeValue()));
1149 // lr();
1150 __ Blr(lr);
1151 DCHECK(!codegen_->IsLeafMethod());
1152 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1153}
1154
1155void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
1156 load->SetLocations(nullptr);
1157}
1158
1159void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) {
1160 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001161 UNUSED(load);
Alexandre Rames5319def2014-10-23 10:03:10 +01001162}
1163
1164void LocationsBuilderARM64::VisitLocal(HLocal* local) {
1165 local->SetLocations(nullptr);
1166}
1167
1168void InstructionCodeGeneratorARM64::VisitLocal(HLocal* local) {
1169 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1170}
1171
1172void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
1173 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1174 locations->SetOut(Location::ConstantLocation(constant));
1175}
1176
1177void InstructionCodeGeneratorARM64::VisitLongConstant(HLongConstant* constant) {
1178 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001179 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001180}
1181
Alexandre Rames42d641b2014-10-27 14:00:51 +00001182void LocationsBuilderARM64::VisitMul(HMul* mul) {
1183 LocationSummary* locations =
1184 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1185 switch (mul->GetResultType()) {
1186 case Primitive::kPrimInt:
1187 case Primitive::kPrimLong:
1188 locations->SetInAt(0, Location::RequiresRegister());
1189 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001190 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00001191 break;
1192
1193 case Primitive::kPrimFloat:
1194 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001195 locations->SetInAt(0, Location::RequiresFpuRegister());
1196 locations->SetInAt(1, Location::RequiresFpuRegister());
1197 locations->SetOut(Location::RequiresFpuRegister());
Alexandre Rames42d641b2014-10-27 14:00:51 +00001198 break;
1199
1200 default:
1201 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1202 }
1203}
1204
1205void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) {
1206 switch (mul->GetResultType()) {
1207 case Primitive::kPrimInt:
1208 case Primitive::kPrimLong:
1209 __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
1210 break;
1211
1212 case Primitive::kPrimFloat:
1213 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001214 __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1));
Alexandre Rames42d641b2014-10-27 14:00:51 +00001215 break;
1216
1217 default:
1218 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
1219 }
1220}
1221
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001222void LocationsBuilderARM64::VisitNeg(HNeg* neg) {
1223 LocationSummary* locations =
1224 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1225 switch (neg->GetResultType()) {
1226 case Primitive::kPrimInt:
1227 case Primitive::kPrimLong: {
1228 locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0)));
1229 locations->SetOut(Location::RequiresRegister());
1230 break;
1231 }
1232
1233 case Primitive::kPrimFloat:
1234 case Primitive::kPrimDouble:
1235 LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
1236 break;
1237
1238 default:
1239 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1240 }
1241}
1242
1243void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
1244 switch (neg->GetResultType()) {
1245 case Primitive::kPrimInt:
1246 case Primitive::kPrimLong:
1247 __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
1248 break;
1249
1250 case Primitive::kPrimFloat:
1251 case Primitive::kPrimDouble:
1252 LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
1253 break;
1254
1255 default:
1256 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1257 }
1258}
1259
1260void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) {
1261 LocationSummary* locations =
1262 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1263 InvokeRuntimeCallingConvention calling_convention;
1264 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
1265 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
1266 locations->SetOut(LocationFrom(x0));
1267 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(2)));
1268}
1269
1270void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
1271 LocationSummary* locations = instruction->GetLocations();
1272 InvokeRuntimeCallingConvention calling_convention;
1273 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
1274 DCHECK(type_index.Is(w0));
1275 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
1276 DCHECK(current_method.Is(w1));
1277 __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
1278 __ Mov(type_index, instruction->GetTypeIndex());
1279 int32_t quick_entrypoint_offset =
1280 QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocArrayWithAccessCheck).Int32Value();
1281 __ Ldr(lr, MemOperand(tr, quick_entrypoint_offset));
1282 __ Blr(lr);
1283 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
1284 DCHECK(!codegen_->IsLeafMethod());
1285}
1286
Alexandre Rames5319def2014-10-23 10:03:10 +01001287void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
1288 LocationSummary* locations =
1289 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1290 InvokeRuntimeCallingConvention calling_convention;
1291 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
1292 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
1293 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
1294}
1295
1296void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) {
1297 LocationSummary* locations = instruction->GetLocations();
1298 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
1299 DCHECK(type_index.Is(w0));
1300 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
1301 DCHECK(current_method.Is(w1));
1302 __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
1303 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001304 int32_t quick_entrypoint_offset =
1305 QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocObjectWithAccessCheck).Int32Value();
1306 __ Ldr(lr, MemOperand(tr, quick_entrypoint_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001307 __ Blr(lr);
1308 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
1309 DCHECK(!codegen_->IsLeafMethod());
1310}
1311
1312void LocationsBuilderARM64::VisitNot(HNot* instruction) {
1313 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Alexandre Rames4e596512014-11-07 15:56:50 +00001314 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001315 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001316}
1317
1318void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
1319 switch (instruction->InputAt(0)->GetType()) {
1320 case Primitive::kPrimBoolean:
1321 __ Eor(OutputRegister(instruction), InputRegisterAt(instruction, 0), Operand(1));
1322 break;
1323
1324 case Primitive::kPrimInt:
Alexandre Rames5319def2014-10-23 10:03:10 +01001325 case Primitive::kPrimLong:
Roland Levillain55dcfb52014-10-24 18:09:09 +01001326 __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
Alexandre Rames5319def2014-10-23 10:03:10 +01001327 break;
1328
1329 default:
1330 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
1331 }
1332}
1333
1334void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
1335 LocationSummary* locations =
1336 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1337 locations->SetInAt(0, Location::RequiresRegister());
1338 if (instruction->HasUses()) {
1339 locations->SetOut(Location::SameAsFirstInput());
1340 }
1341}
1342
1343void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
1344 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction);
1345 codegen_->AddSlowPath(slow_path);
1346
1347 LocationSummary* locations = instruction->GetLocations();
1348 Location obj = locations->InAt(0);
1349 if (obj.IsRegister()) {
1350 __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel());
1351 } else {
1352 DCHECK(obj.IsConstant()) << obj;
1353 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1354 __ B(slow_path->GetEntryLabel());
1355 }
1356}
1357
1358void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
1359 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1360 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1361 if (location.IsStackSlot()) {
1362 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1363 } else if (location.IsDoubleStackSlot()) {
1364 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1365 }
1366 locations->SetOut(location);
1367}
1368
1369void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) {
1370 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001371 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001372}
1373
1374void LocationsBuilderARM64::VisitPhi(HPhi* instruction) {
1375 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1376 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1377 locations->SetInAt(i, Location::Any());
1378 }
1379 locations->SetOut(Location::Any());
1380}
1381
1382void InstructionCodeGeneratorARM64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001383 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001384 LOG(FATAL) << "Unreachable";
1385}
1386
1387void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
1388 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1389 Primitive::Type return_type = instruction->InputAt(0)->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001390 locations->SetInAt(0, ARM64ReturnLocation(return_type));
Alexandre Rames5319def2014-10-23 10:03:10 +01001391}
1392
1393void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001394 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001395 codegen_->GenerateFrameExit();
1396 __ Br(lr);
1397}
1398
1399void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) {
1400 instruction->SetLocations(nullptr);
1401}
1402
1403void InstructionCodeGeneratorARM64::VisitReturnVoid(HReturnVoid* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001404 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001405 codegen_->GenerateFrameExit();
1406 __ Br(lr);
1407}
1408
1409void LocationsBuilderARM64::VisitStoreLocal(HStoreLocal* store) {
1410 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
1411 Primitive::Type field_type = store->InputAt(1)->GetType();
1412 switch (field_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001413 case Primitive::kPrimNot:
Alexandre Rames5319def2014-10-23 10:03:10 +01001414 case Primitive::kPrimBoolean:
1415 case Primitive::kPrimByte:
1416 case Primitive::kPrimChar:
1417 case Primitive::kPrimShort:
1418 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001419 case Primitive::kPrimFloat:
Alexandre Rames5319def2014-10-23 10:03:10 +01001420 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1421 break;
1422
1423 case Primitive::kPrimLong:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001424 case Primitive::kPrimDouble:
Alexandre Rames5319def2014-10-23 10:03:10 +01001425 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1426 break;
1427
1428 default:
1429 LOG(FATAL) << "Unimplemented local type " << field_type;
1430 }
1431}
1432
1433void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001434 UNUSED(store);
Alexandre Rames5319def2014-10-23 10:03:10 +01001435}
1436
1437void LocationsBuilderARM64::VisitSub(HSub* instruction) {
1438 HandleAddSub(instruction);
1439}
1440
1441void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
1442 HandleAddSub(instruction);
1443}
1444
1445void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1446 LocationSummary* locations =
1447 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1448 locations->SetInAt(0, Location::RequiresRegister());
1449 locations->SetInAt(1, Location::RequiresRegister());
1450 if (instruction->HasUses()) {
1451 locations->SetOut(Location::SameAsFirstInput());
1452 }
1453}
1454
1455void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1456 LocationSummary* locations = instruction->GetLocations();
1457 BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(
1458 instruction, locations->InAt(0), locations->InAt(1));
1459 codegen_->AddSlowPath(slow_path);
1460
1461 __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
1462 __ B(slow_path->GetEntryLabel(), hs);
1463}
1464
1465void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
1466 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
1467}
1468
1469void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
1470 // TODO: Improve support for suspend checks.
1471 SuspendCheckSlowPathARM64* slow_path =
1472 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM64(instruction, nullptr);
1473 codegen_->AddSlowPath(slow_path);
1474
1475 __ Subs(wSuspend, wSuspend, 1);
1476 __ B(slow_path->GetEntryLabel(), le);
1477 __ Bind(slow_path->GetReturnLabel());
1478}
1479
1480void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
1481 temp->SetLocations(nullptr);
1482}
1483
1484void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) {
1485 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001486 UNUSED(temp);
Alexandre Rames5319def2014-10-23 10:03:10 +01001487}
1488
1489} // namespace arm64
1490} // namespace art