blob: 430baf65b2163ba98396009d3bc4e07ea00c0e04 [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
Andreas Gampe878d58c2015-01-15 23:24:00 -080019#include "common_arm64.h"
Alexandre Rames5319def2014-10-23 10:03:10 +010020#include "entrypoints/quick/quick_entrypoints.h"
Andreas Gampe1cc7dba2014-12-17 18:43:01 -080021#include "entrypoints/quick/quick_entrypoints_enum.h"
Alexandre Rames5319def2014-10-23 10:03:10 +010022#include "gc/accounting/card_table.h"
Andreas Gampe878d58c2015-01-15 23:24:00 -080023#include "intrinsics.h"
24#include "intrinsics_arm64.h"
Alexandre Rames5319def2014-10-23 10:03:10 +010025#include "mirror/array-inl.h"
26#include "mirror/art_method.h"
27#include "mirror/class.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000028#include "offsets.h"
Alexandre Rames5319def2014-10-23 10:03:10 +010029#include "thread.h"
30#include "utils/arm64/assembler_arm64.h"
31#include "utils/assembler.h"
32#include "utils/stack_checks.h"
33
34
35using namespace vixl; // NOLINT(build/namespaces)
36
37#ifdef __
38#error "ARM64 Codegen VIXL macro-assembler macro already defined."
39#endif
40
Alexandre Rames5319def2014-10-23 10:03:10 +010041namespace art {
42
43namespace arm64 {
44
Andreas Gampe878d58c2015-01-15 23:24:00 -080045using helpers::CPURegisterFrom;
46using helpers::DRegisterFrom;
47using helpers::FPRegisterFrom;
48using helpers::HeapOperand;
49using helpers::HeapOperandFrom;
50using helpers::InputCPURegisterAt;
51using helpers::InputFPRegisterAt;
52using helpers::InputRegisterAt;
53using helpers::InputOperandAt;
54using helpers::Int64ConstantFrom;
Andreas Gampe878d58c2015-01-15 23:24:00 -080055using helpers::LocationFrom;
56using helpers::OperandFromMemOperand;
57using helpers::OutputCPURegister;
58using helpers::OutputFPRegister;
59using helpers::OutputRegister;
60using helpers::RegisterFrom;
61using helpers::StackOperandFrom;
62using helpers::VIXLRegCodeFromART;
63using helpers::WRegisterFrom;
64using helpers::XRegisterFrom;
65
Alexandre Rames5319def2014-10-23 10:03:10 +010066static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>);
67static constexpr int kCurrentMethodStackOffset = 0;
68
Alexandre Rames5319def2014-10-23 10:03:10 +010069inline Condition ARM64Condition(IfCondition cond) {
70 switch (cond) {
71 case kCondEQ: return eq;
72 case kCondNE: return ne;
73 case kCondLT: return lt;
74 case kCondLE: return le;
75 case kCondGT: return gt;
76 case kCondGE: return ge;
77 default:
78 LOG(FATAL) << "Unknown if condition";
79 }
80 return nv; // Unreachable.
81}
82
Alexandre Ramesa89086e2014-11-07 17:13:25 +000083Location ARM64ReturnLocation(Primitive::Type return_type) {
84 DCHECK_NE(return_type, Primitive::kPrimVoid);
85 // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the
86 // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`,
87 // but we use the exact registers for clarity.
88 if (return_type == Primitive::kPrimFloat) {
89 return LocationFrom(s0);
90 } else if (return_type == Primitive::kPrimDouble) {
91 return LocationFrom(d0);
92 } else if (return_type == Primitive::kPrimLong) {
93 return LocationFrom(x0);
94 } else {
95 return LocationFrom(w0);
96 }
97}
98
Alexandre Rames5319def2014-10-23 10:03:10 +010099static const Register kRuntimeParameterCoreRegisters[] = { x0, x1, x2, x3, x4, x5, x6, x7 };
100static constexpr size_t kRuntimeParameterCoreRegistersLength =
101 arraysize(kRuntimeParameterCoreRegisters);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000102static const FPRegister kRuntimeParameterFpuRegisters[] = { d0, d1, d2, d3, d4, d5, d6, d7 };
103static constexpr size_t kRuntimeParameterFpuRegistersLength =
104 arraysize(kRuntimeParameterCoreRegisters);
Alexandre Rames5319def2014-10-23 10:03:10 +0100105
106class InvokeRuntimeCallingConvention : public CallingConvention<Register, FPRegister> {
107 public:
108 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
109
110 InvokeRuntimeCallingConvention()
111 : CallingConvention(kRuntimeParameterCoreRegisters,
112 kRuntimeParameterCoreRegistersLength,
113 kRuntimeParameterFpuRegisters,
114 kRuntimeParameterFpuRegistersLength) {}
115
116 Location GetReturnLocation(Primitive::Type return_type);
117
118 private:
119 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
120};
121
122Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type return_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000123 return ARM64ReturnLocation(return_type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100124}
125
Alexandre Rames67555f72014-11-18 10:55:16 +0000126#define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
127#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
Alexandre Rames5319def2014-10-23 10:03:10 +0100128
Alexandre Rames5319def2014-10-23 10:03:10 +0100129class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
130 public:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000131 BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
132 Location index_location,
133 Location length_location)
134 : instruction_(instruction),
135 index_location_(index_location),
136 length_location_(length_location) {}
137
Alexandre Rames5319def2014-10-23 10:03:10 +0100138
Alexandre Rames67555f72014-11-18 10:55:16 +0000139 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000140 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100141 __ Bind(GetEntryLabel());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000142 // We're moving two locations to locations that could overlap, so we need a parallel
143 // move resolver.
144 InvokeRuntimeCallingConvention calling_convention;
145 codegen->EmitParallelMoves(
146 index_location_, LocationFrom(calling_convention.GetRegisterAt(0)),
147 length_location_, LocationFrom(calling_convention.GetRegisterAt(1)));
148 arm64_codegen->InvokeRuntime(
149 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800150 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Alexandre Rames5319def2014-10-23 10:03:10 +0100151 }
152
153 private:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000154 HBoundsCheck* const instruction_;
155 const Location index_location_;
156 const Location length_location_;
157
Alexandre Rames5319def2014-10-23 10:03:10 +0100158 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
159};
160
Alexandre Rames67555f72014-11-18 10:55:16 +0000161class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 {
162 public:
163 explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : instruction_(instruction) {}
164
165 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
166 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
167 __ Bind(GetEntryLabel());
168 arm64_codegen->InvokeRuntime(
169 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800170 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Alexandre Rames67555f72014-11-18 10:55:16 +0000171 }
172
173 private:
174 HDivZeroCheck* const instruction_;
175 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64);
176};
177
178class LoadClassSlowPathARM64 : public SlowPathCodeARM64 {
179 public:
180 LoadClassSlowPathARM64(HLoadClass* cls,
181 HInstruction* at,
182 uint32_t dex_pc,
183 bool do_clinit)
184 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
185 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
186 }
187
188 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
189 LocationSummary* locations = at_->GetLocations();
190 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
191
192 __ Bind(GetEntryLabel());
193 codegen->SaveLiveRegisters(locations);
194
195 InvokeRuntimeCallingConvention calling_convention;
196 __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
197 arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W());
198 int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
199 : QUICK_ENTRY_POINT(pInitializeType);
200 arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_);
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800201 if (do_clinit_) {
202 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t, mirror::ArtMethod*>();
203 } else {
204 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t, mirror::ArtMethod*>();
205 }
Alexandre Rames67555f72014-11-18 10:55:16 +0000206
207 // Move the class to the desired location.
208 Location out = locations->Out();
209 if (out.IsValid()) {
210 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
211 Primitive::Type type = at_->GetType();
Alexandre Rames3e69f162014-12-10 10:36:50 +0000212 arm64_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
Alexandre Rames67555f72014-11-18 10:55:16 +0000213 }
214
215 codegen->RestoreLiveRegisters(locations);
216 __ B(GetExitLabel());
217 }
218
219 private:
220 // The class this slow path will load.
221 HLoadClass* const cls_;
222
223 // The instruction where this slow path is happening.
224 // (Might be the load class or an initialization check).
225 HInstruction* const at_;
226
227 // The dex PC of `at_`.
228 const uint32_t dex_pc_;
229
230 // Whether to initialize the class.
231 const bool do_clinit_;
232
233 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
234};
235
236class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
237 public:
238 explicit LoadStringSlowPathARM64(HLoadString* instruction) : instruction_(instruction) {}
239
240 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
241 LocationSummary* locations = instruction_->GetLocations();
242 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
243 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
244
245 __ Bind(GetEntryLabel());
246 codegen->SaveLiveRegisters(locations);
247
248 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800249 arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W());
250 __ Mov(calling_convention.GetRegisterAt(0).W(), instruction_->GetStringIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +0000251 arm64_codegen->InvokeRuntime(
252 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800253 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t, mirror::ArtMethod*>();
Alexandre Rames67555f72014-11-18 10:55:16 +0000254 Primitive::Type type = instruction_->GetType();
Alexandre Rames3e69f162014-12-10 10:36:50 +0000255 arm64_codegen->MoveLocation(locations->Out(), calling_convention.GetReturnLocation(type), type);
Alexandre Rames67555f72014-11-18 10:55:16 +0000256
257 codegen->RestoreLiveRegisters(locations);
258 __ B(GetExitLabel());
259 }
260
261 private:
262 HLoadString* const instruction_;
263
264 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
265};
266
Alexandre Rames5319def2014-10-23 10:03:10 +0100267class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
268 public:
269 explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {}
270
Alexandre Rames67555f72014-11-18 10:55:16 +0000271 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
272 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100273 __ Bind(GetEntryLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000274 arm64_codegen->InvokeRuntime(
275 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800276 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Alexandre Rames5319def2014-10-23 10:03:10 +0100277 }
278
279 private:
280 HNullCheck* const instruction_;
281
282 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM64);
283};
284
285class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 {
286 public:
287 explicit SuspendCheckSlowPathARM64(HSuspendCheck* instruction,
288 HBasicBlock* successor)
289 : instruction_(instruction), successor_(successor) {}
290
Alexandre Rames67555f72014-11-18 10:55:16 +0000291 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
292 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
Alexandre Rames5319def2014-10-23 10:03:10 +0100293 __ Bind(GetEntryLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000294 codegen->SaveLiveRegisters(instruction_->GetLocations());
295 arm64_codegen->InvokeRuntime(
296 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800297 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Alexandre Rames67555f72014-11-18 10:55:16 +0000298 codegen->RestoreLiveRegisters(instruction_->GetLocations());
299 if (successor_ == nullptr) {
300 __ B(GetReturnLabel());
301 } else {
302 __ B(arm64_codegen->GetLabelOf(successor_));
303 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100304 }
305
306 vixl::Label* GetReturnLabel() {
307 DCHECK(successor_ == nullptr);
308 return &return_label_;
309 }
310
Alexandre Rames5319def2014-10-23 10:03:10 +0100311 private:
312 HSuspendCheck* const instruction_;
313 // If not null, the block to branch to after the suspend check.
314 HBasicBlock* const successor_;
315
316 // If `successor_` is null, the label to branch to after the suspend check.
317 vixl::Label return_label_;
318
319 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
320};
321
Alexandre Rames67555f72014-11-18 10:55:16 +0000322class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
323 public:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000324 TypeCheckSlowPathARM64(HInstruction* instruction,
325 Location class_to_check,
326 Location object_class,
327 uint32_t dex_pc)
328 : instruction_(instruction),
329 class_to_check_(class_to_check),
330 object_class_(object_class),
331 dex_pc_(dex_pc) {}
Alexandre Rames67555f72014-11-18 10:55:16 +0000332
333 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000334 LocationSummary* locations = instruction_->GetLocations();
335 DCHECK(instruction_->IsCheckCast()
336 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
337 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
338
Alexandre Rames67555f72014-11-18 10:55:16 +0000339 __ Bind(GetEntryLabel());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000340 codegen->SaveLiveRegisters(locations);
341
342 // We're moving two locations to locations that could overlap, so we need a parallel
343 // move resolver.
344 InvokeRuntimeCallingConvention calling_convention;
345 codegen->EmitParallelMoves(
346 class_to_check_, LocationFrom(calling_convention.GetRegisterAt(0)),
347 object_class_, LocationFrom(calling_convention.GetRegisterAt(1)));
348
349 if (instruction_->IsInstanceOf()) {
350 arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_);
351 Primitive::Type ret_type = instruction_->GetType();
352 Location ret_loc = calling_convention.GetReturnLocation(ret_type);
353 arm64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800354 CheckEntrypointTypes<kQuickInstanceofNonTrivial, uint32_t,
355 const mirror::Class*, const mirror::Class*>();
Alexandre Rames3e69f162014-12-10 10:36:50 +0000356 } else {
357 DCHECK(instruction_->IsCheckCast());
358 arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_);
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800359 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
Alexandre Rames3e69f162014-12-10 10:36:50 +0000360 }
361
362 codegen->RestoreLiveRegisters(locations);
Serban Constantinescu02164b32014-11-13 14:05:07 +0000363 __ B(GetExitLabel());
Alexandre Rames67555f72014-11-18 10:55:16 +0000364 }
365
366 private:
Alexandre Rames3e69f162014-12-10 10:36:50 +0000367 HInstruction* const instruction_;
368 const Location class_to_check_;
369 const Location object_class_;
370 uint32_t dex_pc_;
371
Alexandre Rames67555f72014-11-18 10:55:16 +0000372 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64);
373};
374
Alexandre Rames5319def2014-10-23 10:03:10 +0100375#undef __
376
377Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
378 Location next_location;
379 if (type == Primitive::kPrimVoid) {
380 LOG(FATAL) << "Unreachable type " << type;
381 }
382
Alexandre Rames542361f2015-01-29 16:57:31 +0000383 if (Primitive::IsFloatingPointType(type) &&
384 (fp_index_ < calling_convention.GetNumberOfFpuRegisters())) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000385 next_location = LocationFrom(calling_convention.GetFpuRegisterAt(fp_index_++));
Alexandre Rames542361f2015-01-29 16:57:31 +0000386 } else if (!Primitive::IsFloatingPointType(type) &&
387 (gp_index_ < calling_convention.GetNumberOfRegisters())) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000388 next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++));
389 } else {
390 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
Alexandre Rames542361f2015-01-29 16:57:31 +0000391 next_location = Primitive::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
392 : Location::StackSlot(stack_offset);
Alexandre Rames5319def2014-10-23 10:03:10 +0100393 }
394
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000395 // Space on the stack is reserved for all arguments.
Alexandre Rames542361f2015-01-29 16:57:31 +0000396 stack_index_ += Primitive::Is64BitType(type) ? 2 : 1;
Alexandre Rames5319def2014-10-23 10:03:10 +0100397 return next_location;
398}
399
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000400CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph, const CompilerOptions& compiler_options)
Alexandre Rames5319def2014-10-23 10:03:10 +0100401 : CodeGenerator(graph,
402 kNumberOfAllocatableRegisters,
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000403 kNumberOfAllocatableFPRegisters,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000404 kNumberOfAllocatableRegisterPairs,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000405 (1 << LR),
Nicolas Geoffray98893962015-01-21 12:32:32 +0000406 0,
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000407 compiler_options),
Alexandre Rames5319def2014-10-23 10:03:10 +0100408 block_labels_(nullptr),
409 location_builder_(graph, this),
Alexandre Rames3e69f162014-12-10 10:36:50 +0000410 instruction_visitor_(graph, this),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000411 move_resolver_(graph->GetArena(), this) {
412 // Save the link register (containing the return address) to mimic Quick.
413 AddAllocatedRegister(Location::RegisterLocation(LR));
414}
Alexandre Rames5319def2014-10-23 10:03:10 +0100415
Alexandre Rames67555f72014-11-18 10:55:16 +0000416#undef __
417#define __ GetVIXLAssembler()->
Alexandre Rames5319def2014-10-23 10:03:10 +0100418
Serban Constantinescu32f5b4d2014-11-25 20:05:46 +0000419void CodeGeneratorARM64::Finalize(CodeAllocator* allocator) {
420 // Ensure we emit the literal pool.
421 __ FinalizeCode();
422 CodeGenerator::Finalize(allocator);
423}
424
Alexandre Rames3e69f162014-12-10 10:36:50 +0000425void ParallelMoveResolverARM64::EmitMove(size_t index) {
426 MoveOperands* move = moves_.Get(index);
427 codegen_->MoveLocation(move->GetDestination(), move->GetSource());
428}
429
430void ParallelMoveResolverARM64::EmitSwap(size_t index) {
431 MoveOperands* move = moves_.Get(index);
432 codegen_->SwapLocations(move->GetDestination(), move->GetSource());
433}
434
435void ParallelMoveResolverARM64::RestoreScratch(int reg) {
436 __ Pop(Register(VIXLRegCodeFromART(reg), kXRegSize));
437}
438
439void ParallelMoveResolverARM64::SpillScratch(int reg) {
440 __ Push(Register(VIXLRegCodeFromART(reg), kXRegSize));
441}
442
Alexandre Rames5319def2014-10-23 10:03:10 +0100443void CodeGeneratorARM64::GenerateFrameEntry() {
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000444 __ Bind(&frame_entry_label_);
445
Serban Constantinescu02164b32014-11-13 14:05:07 +0000446 bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kArm64) || !IsLeafMethod();
447 if (do_overflow_check) {
448 UseScratchRegisterScope temps(GetVIXLAssembler());
449 Register temp = temps.AcquireX();
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000450 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
451 __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
452 __ Ldr(wzr, MemOperand(temp, 0));
453 RecordPcInfo(nullptr, 0);
Serban Constantinescu02164b32014-11-13 14:05:07 +0000454 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100455
Alexandre Rames5319def2014-10-23 10:03:10 +0100456 int frame_size = GetFrameSize();
Andreas Gampe878d58c2015-01-15 23:24:00 -0800457 __ Str(kArtMethodRegister, MemOperand(sp, -frame_size, PreIndex));
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000458 __ PokeCPURegList(GetFramePreservedRegisters(), frame_size - FrameEntrySpillSize());
Alexandre Rames5319def2014-10-23 10:03:10 +0100459
460 // Stack layout:
461 // sp[frame_size - 8] : lr.
462 // ... : other preserved registers.
463 // sp[frame_size - regs_size]: first preserved register.
464 // ... : reserved frame space.
Alexandre Rames67555f72014-11-18 10:55:16 +0000465 // sp[0] : current method.
Alexandre Rames5319def2014-10-23 10:03:10 +0100466}
467
468void CodeGeneratorARM64::GenerateFrameExit() {
469 int frame_size = GetFrameSize();
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000470 __ PeekCPURegList(GetFramePreservedRegisters(), frame_size - FrameEntrySpillSize());
Alexandre Rames5319def2014-10-23 10:03:10 +0100471 __ Drop(frame_size);
472}
473
474void CodeGeneratorARM64::Bind(HBasicBlock* block) {
475 __ Bind(GetLabelOf(block));
476}
477
Alexandre Rames5319def2014-10-23 10:03:10 +0100478void CodeGeneratorARM64::Move(HInstruction* instruction,
479 Location location,
480 HInstruction* move_for) {
481 LocationSummary* locations = instruction->GetLocations();
482 if (locations != nullptr && locations->Out().Equals(location)) {
483 return;
484 }
485
486 Primitive::Type type = instruction->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000487 DCHECK_NE(type, Primitive::kPrimVoid);
Alexandre Rames5319def2014-10-23 10:03:10 +0100488
489 if (instruction->IsIntConstant() || instruction->IsLongConstant()) {
490 int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue()
491 : instruction->AsLongConstant()->GetValue();
492 if (location.IsRegister()) {
493 Register dst = RegisterFrom(location, type);
494 DCHECK((instruction->IsIntConstant() && dst.Is32Bits()) ||
495 (instruction->IsLongConstant() && dst.Is64Bits()));
496 __ Mov(dst, value);
497 } else {
498 DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
Alexandre Rames67555f72014-11-18 10:55:16 +0000499 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100500 Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
501 __ Mov(temp, value);
502 __ Str(temp, StackOperandFrom(location));
503 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000504 } else if (instruction->IsTemporary()) {
505 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000506 MoveLocation(location, temp_location, type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100507 } else if (instruction->IsLoadLocal()) {
508 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Alexandre Rames542361f2015-01-29 16:57:31 +0000509 if (Primitive::Is64BitType(type)) {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000510 MoveLocation(location, Location::DoubleStackSlot(stack_slot), type);
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000511 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000512 MoveLocation(location, Location::StackSlot(stack_slot), type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100513 }
514
515 } else {
516 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000517 MoveLocation(location, locations->Out(), type);
Alexandre Rames5319def2014-10-23 10:03:10 +0100518 }
519}
520
Alexandre Rames5319def2014-10-23 10:03:10 +0100521Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const {
522 Primitive::Type type = load->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000523
Alexandre Rames5319def2014-10-23 10:03:10 +0100524 switch (type) {
525 case Primitive::kPrimNot:
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000526 case Primitive::kPrimInt:
527 case Primitive::kPrimFloat:
528 return Location::StackSlot(GetStackSlot(load->GetLocal()));
529
530 case Primitive::kPrimLong:
531 case Primitive::kPrimDouble:
532 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
533
Alexandre Rames5319def2014-10-23 10:03:10 +0100534 case Primitive::kPrimBoolean:
535 case Primitive::kPrimByte:
536 case Primitive::kPrimChar:
537 case Primitive::kPrimShort:
Alexandre Rames5319def2014-10-23 10:03:10 +0100538 case Primitive::kPrimVoid:
Alexandre Rames5319def2014-10-23 10:03:10 +0100539 LOG(FATAL) << "Unexpected type " << type;
540 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000541
Alexandre Rames5319def2014-10-23 10:03:10 +0100542 LOG(FATAL) << "Unreachable";
543 return Location::NoLocation();
544}
545
546void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
Alexandre Rames67555f72014-11-18 10:55:16 +0000547 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames5319def2014-10-23 10:03:10 +0100548 Register card = temps.AcquireX();
Serban Constantinescu02164b32014-11-13 14:05:07 +0000549 Register temp = temps.AcquireW(); // Index within the CardTable - 32bit.
Alexandre Rames5319def2014-10-23 10:03:10 +0100550 vixl::Label done;
551 __ Cbz(value, &done);
552 __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
553 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
Serban Constantinescu02164b32014-11-13 14:05:07 +0000554 __ Strb(card, MemOperand(card, temp.X()));
Alexandre Rames5319def2014-10-23 10:03:10 +0100555 __ Bind(&done);
556}
557
Nicolas Geoffray98893962015-01-21 12:32:32 +0000558void CodeGeneratorARM64::SetupBlockedRegisters(bool is_baseline ATTRIBUTE_UNUSED) const {
Alexandre Rames5319def2014-10-23 10:03:10 +0100559 // Block reserved registers:
560 // ip0 (VIXL temporary)
561 // ip1 (VIXL temporary)
Serban Constantinescu02164b32014-11-13 14:05:07 +0000562 // tr
Alexandre Rames5319def2014-10-23 10:03:10 +0100563 // lr
564 // sp is not part of the allocatable registers, so we don't need to block it.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000565 // TODO: Avoid blocking callee-saved registers, and instead preserve them
566 // where necessary.
Alexandre Rames5319def2014-10-23 10:03:10 +0100567 CPURegList reserved_core_registers = vixl_reserved_core_registers;
568 reserved_core_registers.Combine(runtime_reserved_core_registers);
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000569 reserved_core_registers.Combine(quick_callee_saved_registers);
Alexandre Rames5319def2014-10-23 10:03:10 +0100570 while (!reserved_core_registers.IsEmpty()) {
571 blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true;
572 }
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000573 CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
574 reserved_fp_registers.Combine(CPURegList::GetCalleeSavedFP());
575 while (!reserved_core_registers.IsEmpty()) {
576 blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().code()] = true;
577 }
Alexandre Rames5319def2014-10-23 10:03:10 +0100578}
579
580Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const {
581 if (type == Primitive::kPrimVoid) {
582 LOG(FATAL) << "Unreachable type " << type;
583 }
584
Alexandre Rames542361f2015-01-29 16:57:31 +0000585 if (Primitive::IsFloatingPointType(type)) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000586 ssize_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfAllocatableFPRegisters);
587 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100588 return Location::FpuRegisterLocation(reg);
589 } else {
Alexandre Ramesa89086e2014-11-07 17:13:25 +0000590 ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfAllocatableRegisters);
591 DCHECK_NE(reg, -1);
Alexandre Rames5319def2014-10-23 10:03:10 +0100592 return Location::RegisterLocation(reg);
593 }
594}
595
Alexandre Rames3e69f162014-12-10 10:36:50 +0000596size_t CodeGeneratorARM64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
597 Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
598 __ Str(reg, MemOperand(sp, stack_index));
599 return kArm64WordSize;
600}
601
602size_t CodeGeneratorARM64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
603 Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
604 __ Ldr(reg, MemOperand(sp, stack_index));
605 return kArm64WordSize;
606}
607
608size_t CodeGeneratorARM64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
609 FPRegister reg = FPRegister(reg_id, kDRegSize);
610 __ Str(reg, MemOperand(sp, stack_index));
611 return kArm64WordSize;
612}
613
614size_t CodeGeneratorARM64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
615 FPRegister reg = FPRegister(reg_id, kDRegSize);
616 __ Ldr(reg, MemOperand(sp, stack_index));
617 return kArm64WordSize;
618}
619
Alexandre Rames5319def2014-10-23 10:03:10 +0100620void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
621 stream << Arm64ManagedRegister::FromXRegister(XRegister(reg));
622}
623
624void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
625 stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
626}
627
Alexandre Rames67555f72014-11-18 10:55:16 +0000628void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
629 if (constant->IsIntConstant() || constant->IsLongConstant()) {
630 __ Mov(Register(destination),
631 constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
632 : constant->AsLongConstant()->GetValue());
633 } else if (constant->IsFloatConstant()) {
634 __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
635 } else {
636 DCHECK(constant->IsDoubleConstant());
637 __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue());
638 }
639}
640
Alexandre Rames3e69f162014-12-10 10:36:50 +0000641
642static bool CoherentConstantAndType(Location constant, Primitive::Type type) {
643 DCHECK(constant.IsConstant());
644 HConstant* cst = constant.GetConstant();
645 return (cst->IsIntConstant() && type == Primitive::kPrimInt) ||
646 (cst->IsLongConstant() && type == Primitive::kPrimLong) ||
647 (cst->IsFloatConstant() && type == Primitive::kPrimFloat) ||
648 (cst->IsDoubleConstant() && type == Primitive::kPrimDouble);
649}
650
651void CodeGeneratorARM64::MoveLocation(Location destination, Location source, Primitive::Type type) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000652 if (source.Equals(destination)) {
653 return;
654 }
Alexandre Rames3e69f162014-12-10 10:36:50 +0000655
656 // A valid move can always be inferred from the destination and source
657 // locations. When moving from and to a register, the argument type can be
658 // used to generate 32bit instead of 64bit moves. In debug mode we also
659 // checks the coherency of the locations and the type.
660 bool unspecified_type = (type == Primitive::kPrimVoid);
661
662 if (destination.IsRegister() || destination.IsFpuRegister()) {
663 if (unspecified_type) {
664 HConstant* src_cst = source.IsConstant() ? source.GetConstant() : nullptr;
665 if (source.IsStackSlot() ||
666 (src_cst != nullptr && (src_cst->IsIntConstant() || src_cst->IsFloatConstant()))) {
667 // For stack slots and 32bit constants, a 64bit type is appropriate.
668 type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
Alexandre Rames67555f72014-11-18 10:55:16 +0000669 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +0000670 // If the source is a double stack slot or a 64bit constant, a 64bit
671 // type is appropriate. Else the source is a register, and since the
672 // type has not been specified, we chose a 64bit type to force a 64bit
673 // move.
674 type = destination.IsRegister() ? Primitive::kPrimLong : Primitive::kPrimDouble;
Alexandre Rames67555f72014-11-18 10:55:16 +0000675 }
Alexandre Rames3e69f162014-12-10 10:36:50 +0000676 }
Alexandre Rames542361f2015-01-29 16:57:31 +0000677 DCHECK((destination.IsFpuRegister() && Primitive::IsFloatingPointType(type)) ||
678 (destination.IsRegister() && !Primitive::IsFloatingPointType(type)));
Alexandre Rames3e69f162014-12-10 10:36:50 +0000679 CPURegister dst = CPURegisterFrom(destination, type);
680 if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
681 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
682 __ Ldr(dst, StackOperandFrom(source));
683 } else if (source.IsConstant()) {
684 DCHECK(CoherentConstantAndType(source, type));
685 MoveConstant(dst, source.GetConstant());
686 } else {
687 if (destination.IsRegister()) {
688 __ Mov(Register(dst), RegisterFrom(source, type));
689 } else {
690 __ Fmov(FPRegister(dst), FPRegisterFrom(source, type));
691 }
692 }
693
694 } else { // The destination is not a register. It must be a stack slot.
695 DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
696 if (source.IsRegister() || source.IsFpuRegister()) {
697 if (unspecified_type) {
698 if (source.IsRegister()) {
699 type = destination.IsStackSlot() ? Primitive::kPrimInt : Primitive::kPrimLong;
700 } else {
701 type = destination.IsStackSlot() ? Primitive::kPrimFloat : Primitive::kPrimDouble;
702 }
703 }
Alexandre Rames542361f2015-01-29 16:57:31 +0000704 DCHECK((destination.IsDoubleStackSlot() == Primitive::Is64BitType(type)) &&
705 (source.IsFpuRegister() == Primitive::IsFloatingPointType(type)));
Alexandre Rames3e69f162014-12-10 10:36:50 +0000706 __ Str(CPURegisterFrom(source, type), StackOperandFrom(destination));
707 } else if (source.IsConstant()) {
708 DCHECK(unspecified_type || CoherentConstantAndType(source, type));
709 UseScratchRegisterScope temps(GetVIXLAssembler());
710 HConstant* src_cst = source.GetConstant();
711 CPURegister temp;
712 if (src_cst->IsIntConstant()) {
713 temp = temps.AcquireW();
714 } else if (src_cst->IsLongConstant()) {
715 temp = temps.AcquireX();
716 } else if (src_cst->IsFloatConstant()) {
717 temp = temps.AcquireS();
718 } else {
719 DCHECK(src_cst->IsDoubleConstant());
720 temp = temps.AcquireD();
721 }
722 MoveConstant(temp, src_cst);
Alexandre Rames67555f72014-11-18 10:55:16 +0000723 __ Str(temp, StackOperandFrom(destination));
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000724 } else {
Alexandre Rames67555f72014-11-18 10:55:16 +0000725 DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000726 DCHECK(source.IsDoubleStackSlot() == destination.IsDoubleStackSlot());
Alexandre Rames67555f72014-11-18 10:55:16 +0000727 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Rames3e69f162014-12-10 10:36:50 +0000728 // There is generally less pressure on FP registers.
729 FPRegister temp = destination.IsDoubleStackSlot() ? temps.AcquireD() : temps.AcquireS();
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000730 __ Ldr(temp, StackOperandFrom(source));
731 __ Str(temp, StackOperandFrom(destination));
732 }
733 }
734}
735
Alexandre Rames3e69f162014-12-10 10:36:50 +0000736void CodeGeneratorARM64::SwapLocations(Location loc1, Location loc2) {
737 DCHECK(!loc1.IsConstant());
738 DCHECK(!loc2.IsConstant());
739
740 if (loc1.Equals(loc2)) {
741 return;
742 }
743
744 UseScratchRegisterScope temps(GetAssembler()->vixl_masm_);
745
746 bool is_slot1 = loc1.IsStackSlot() || loc1.IsDoubleStackSlot();
747 bool is_slot2 = loc2.IsStackSlot() || loc2.IsDoubleStackSlot();
748 bool is_fp_reg1 = loc1.IsFpuRegister();
749 bool is_fp_reg2 = loc2.IsFpuRegister();
750
751 if (loc2.IsRegister() && loc1.IsRegister()) {
752 Register r1 = XRegisterFrom(loc1);
753 Register r2 = XRegisterFrom(loc2);
754 Register tmp = temps.AcquireSameSizeAs(r1);
755 __ Mov(tmp, r2);
756 __ Mov(r2, r1);
757 __ Mov(r1, tmp);
758 } else if (is_fp_reg2 && is_fp_reg1) {
759 FPRegister r1 = DRegisterFrom(loc1);
760 FPRegister r2 = DRegisterFrom(loc2);
761 FPRegister tmp = temps.AcquireSameSizeAs(r1);
762 __ Fmov(tmp, r2);
763 __ Fmov(r2, r1);
764 __ Fmov(r1, tmp);
765 } else if (is_slot1 != is_slot2) {
766 MemOperand mem = StackOperandFrom(is_slot1 ? loc1 : loc2);
767 Location reg_loc = is_slot1 ? loc2 : loc1;
768 CPURegister reg, tmp;
769 if (reg_loc.IsFpuRegister()) {
770 reg = DRegisterFrom(reg_loc);
771 tmp = temps.AcquireD();
772 } else {
773 reg = XRegisterFrom(reg_loc);
774 tmp = temps.AcquireX();
775 }
776 __ Ldr(tmp, mem);
777 __ Str(reg, mem);
778 if (reg_loc.IsFpuRegister()) {
779 __ Fmov(FPRegister(reg), FPRegister(tmp));
780 } else {
781 __ Mov(Register(reg), Register(tmp));
782 }
783 } else if (is_slot1 && is_slot2) {
784 MemOperand mem1 = StackOperandFrom(loc1);
785 MemOperand mem2 = StackOperandFrom(loc2);
786 Register tmp1 = loc1.IsStackSlot() ? temps.AcquireW() : temps.AcquireX();
787 Register tmp2 = temps.AcquireSameSizeAs(tmp1);
788 __ Ldr(tmp1, mem1);
789 __ Ldr(tmp2, mem2);
790 __ Str(tmp1, mem2);
791 __ Str(tmp2, mem1);
792 } else {
793 LOG(FATAL) << "Unimplemented";
794 }
795}
796
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000797void CodeGeneratorARM64::Load(Primitive::Type type,
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000798 CPURegister dst,
799 const MemOperand& src) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000800 switch (type) {
801 case Primitive::kPrimBoolean:
Alexandre Rames67555f72014-11-18 10:55:16 +0000802 __ Ldrb(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000803 break;
804 case Primitive::kPrimByte:
Alexandre Rames67555f72014-11-18 10:55:16 +0000805 __ Ldrsb(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000806 break;
807 case Primitive::kPrimShort:
Alexandre Rames67555f72014-11-18 10:55:16 +0000808 __ Ldrsh(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000809 break;
810 case Primitive::kPrimChar:
Alexandre Rames67555f72014-11-18 10:55:16 +0000811 __ Ldrh(Register(dst), src);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000812 break;
813 case Primitive::kPrimInt:
814 case Primitive::kPrimNot:
815 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000816 case Primitive::kPrimFloat:
817 case Primitive::kPrimDouble:
Alexandre Rames542361f2015-01-29 16:57:31 +0000818 DCHECK_EQ(dst.Is64Bits(), Primitive::Is64BitType(type));
Alexandre Rames67555f72014-11-18 10:55:16 +0000819 __ Ldr(dst, src);
820 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000821 case Primitive::kPrimVoid:
822 LOG(FATAL) << "Unreachable type " << type;
823 }
824}
825
Calin Juravle77520bc2015-01-12 18:45:46 +0000826void CodeGeneratorARM64::LoadAcquire(HInstruction* instruction,
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000827 CPURegister dst,
828 const MemOperand& src) {
829 UseScratchRegisterScope temps(GetVIXLAssembler());
830 Register temp_base = temps.AcquireX();
Calin Juravle77520bc2015-01-12 18:45:46 +0000831 Primitive::Type type = instruction->GetType();
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000832
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000833 DCHECK(!src.IsPreIndex());
834 DCHECK(!src.IsPostIndex());
835
836 // TODO(vixl): Let the MacroAssembler handle MemOperand.
Andreas Gampe878d58c2015-01-15 23:24:00 -0800837 __ Add(temp_base, src.base(), OperandFromMemOperand(src));
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000838 MemOperand base = MemOperand(temp_base);
839 switch (type) {
840 case Primitive::kPrimBoolean:
841 __ Ldarb(Register(dst), base);
Calin Juravle77520bc2015-01-12 18:45:46 +0000842 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000843 break;
844 case Primitive::kPrimByte:
845 __ Ldarb(Register(dst), base);
Calin Juravle77520bc2015-01-12 18:45:46 +0000846 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000847 __ Sbfx(Register(dst), Register(dst), 0, Primitive::ComponentSize(type) * kBitsPerByte);
848 break;
849 case Primitive::kPrimChar:
850 __ Ldarh(Register(dst), base);
Calin Juravle77520bc2015-01-12 18:45:46 +0000851 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000852 break;
853 case Primitive::kPrimShort:
854 __ Ldarh(Register(dst), base);
Calin Juravle77520bc2015-01-12 18:45:46 +0000855 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000856 __ Sbfx(Register(dst), Register(dst), 0, Primitive::ComponentSize(type) * kBitsPerByte);
857 break;
858 case Primitive::kPrimInt:
859 case Primitive::kPrimNot:
860 case Primitive::kPrimLong:
Alexandre Rames542361f2015-01-29 16:57:31 +0000861 DCHECK_EQ(dst.Is64Bits(), Primitive::Is64BitType(type));
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000862 __ Ldar(Register(dst), base);
Calin Juravle77520bc2015-01-12 18:45:46 +0000863 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000864 break;
865 case Primitive::kPrimFloat:
866 case Primitive::kPrimDouble: {
867 DCHECK(dst.IsFPRegister());
Alexandre Rames542361f2015-01-29 16:57:31 +0000868 DCHECK_EQ(dst.Is64Bits(), Primitive::Is64BitType(type));
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000869
870 Register temp = dst.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
871 __ Ldar(temp, base);
Calin Juravle77520bc2015-01-12 18:45:46 +0000872 MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000873 __ Fmov(FPRegister(dst), temp);
874 break;
875 }
876 case Primitive::kPrimVoid:
877 LOG(FATAL) << "Unreachable type " << type;
878 }
879}
880
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000881void CodeGeneratorARM64::Store(Primitive::Type type,
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000882 CPURegister src,
883 const MemOperand& dst) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000884 switch (type) {
885 case Primitive::kPrimBoolean:
886 case Primitive::kPrimByte:
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000887 __ Strb(Register(src), dst);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000888 break;
889 case Primitive::kPrimChar:
890 case Primitive::kPrimShort:
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000891 __ Strh(Register(src), dst);
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000892 break;
893 case Primitive::kPrimInt:
894 case Primitive::kPrimNot:
895 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000896 case Primitive::kPrimFloat:
897 case Primitive::kPrimDouble:
Alexandre Rames542361f2015-01-29 16:57:31 +0000898 DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000899 __ Str(src, dst);
Alexandre Rames67555f72014-11-18 10:55:16 +0000900 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +0000901 case Primitive::kPrimVoid:
902 LOG(FATAL) << "Unreachable type " << type;
903 }
904}
905
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000906void CodeGeneratorARM64::StoreRelease(Primitive::Type type,
907 CPURegister src,
908 const MemOperand& dst) {
909 UseScratchRegisterScope temps(GetVIXLAssembler());
910 Register temp_base = temps.AcquireX();
911
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000912 DCHECK(!dst.IsPreIndex());
913 DCHECK(!dst.IsPostIndex());
914
915 // TODO(vixl): Let the MacroAssembler handle this.
Andreas Gampe878d58c2015-01-15 23:24:00 -0800916 Operand op = OperandFromMemOperand(dst);
917 __ Add(temp_base, dst.base(), op);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000918 MemOperand base = MemOperand(temp_base);
919 switch (type) {
920 case Primitive::kPrimBoolean:
921 case Primitive::kPrimByte:
922 __ Stlrb(Register(src), base);
923 break;
924 case Primitive::kPrimChar:
925 case Primitive::kPrimShort:
926 __ Stlrh(Register(src), base);
927 break;
928 case Primitive::kPrimInt:
929 case Primitive::kPrimNot:
930 case Primitive::kPrimLong:
Alexandre Rames542361f2015-01-29 16:57:31 +0000931 DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000932 __ Stlr(Register(src), base);
933 break;
934 case Primitive::kPrimFloat:
935 case Primitive::kPrimDouble: {
936 DCHECK(src.IsFPRegister());
Alexandre Rames542361f2015-01-29 16:57:31 +0000937 DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000938
939 Register temp = src.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
940 __ Fmov(temp, FPRegister(src));
941 __ Stlr(temp, base);
942 break;
943 }
944 case Primitive::kPrimVoid:
945 LOG(FATAL) << "Unreachable type " << type;
946 }
947}
948
Alexandre Rames67555f72014-11-18 10:55:16 +0000949void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) {
950 DCHECK(current_method.IsW());
951 __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
952}
953
954void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
955 HInstruction* instruction,
956 uint32_t dex_pc) {
957 __ Ldr(lr, MemOperand(tr, entry_point_offset));
958 __ Blr(lr);
Serban Constantinescu02164b32014-11-13 14:05:07 +0000959 if (instruction != nullptr) {
960 RecordPcInfo(instruction, dex_pc);
961 DCHECK(instruction->IsSuspendCheck()
962 || instruction->IsBoundsCheck()
963 || instruction->IsNullCheck()
964 || instruction->IsDivZeroCheck()
965 || !IsLeafMethod());
966 }
Alexandre Rames67555f72014-11-18 10:55:16 +0000967}
968
969void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
970 vixl::Register class_reg) {
971 UseScratchRegisterScope temps(GetVIXLAssembler());
972 Register temp = temps.AcquireW();
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000973 size_t status_offset = mirror::Class::StatusOffset().SizeValue();
974
Serban Constantinescu02164b32014-11-13 14:05:07 +0000975 // Even if the initialized flag is set, we need to ensure consistent memory ordering.
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000976 if (kUseAcquireRelease) {
977 // TODO(vixl): Let the MacroAssembler handle MemOperand.
978 __ Add(temp, class_reg, status_offset);
979 __ Ldar(temp, HeapOperand(temp));
980 __ Cmp(temp, mirror::Class::kStatusInitialized);
981 __ B(lt, slow_path->GetEntryLabel());
982 } else {
983 __ Ldr(temp, HeapOperand(class_reg, status_offset));
984 __ Cmp(temp, mirror::Class::kStatusInitialized);
985 __ B(lt, slow_path->GetEntryLabel());
986 __ Dmb(InnerShareable, BarrierReads);
987 }
Alexandre Rames67555f72014-11-18 10:55:16 +0000988 __ Bind(slow_path->GetExitLabel());
989}
Alexandre Rames5319def2014-10-23 10:03:10 +0100990
Serban Constantinescu02d81cc2015-01-05 16:08:49 +0000991void InstructionCodeGeneratorARM64::GenerateMemoryBarrier(MemBarrierKind kind) {
992 BarrierType type = BarrierAll;
993
994 switch (kind) {
995 case MemBarrierKind::kAnyAny:
996 case MemBarrierKind::kAnyStore: {
997 type = BarrierAll;
998 break;
999 }
1000 case MemBarrierKind::kLoadAny: {
1001 type = BarrierReads;
1002 break;
1003 }
1004 case MemBarrierKind::kStoreStore: {
1005 type = BarrierWrites;
1006 break;
1007 }
1008 default:
1009 LOG(FATAL) << "Unexpected memory barrier " << kind;
1010 }
1011 __ Dmb(InnerShareable, type);
1012}
1013
Serban Constantinescu02164b32014-11-13 14:05:07 +00001014void InstructionCodeGeneratorARM64::GenerateSuspendCheck(HSuspendCheck* instruction,
1015 HBasicBlock* successor) {
1016 SuspendCheckSlowPathARM64* slow_path =
1017 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM64(instruction, successor);
1018 codegen_->AddSlowPath(slow_path);
1019 UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
1020 Register temp = temps.AcquireW();
1021
1022 __ Ldrh(temp, MemOperand(tr, Thread::ThreadFlagsOffset<kArm64WordSize>().SizeValue()));
1023 if (successor == nullptr) {
1024 __ Cbnz(temp, slow_path->GetEntryLabel());
1025 __ Bind(slow_path->GetReturnLabel());
1026 } else {
1027 __ Cbz(temp, codegen_->GetLabelOf(successor));
1028 __ B(slow_path->GetEntryLabel());
1029 // slow_path will return to GetLabelOf(successor).
1030 }
1031}
1032
Alexandre Rames5319def2014-10-23 10:03:10 +01001033InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
1034 CodeGeneratorARM64* codegen)
1035 : HGraphVisitor(graph),
1036 assembler_(codegen->GetAssembler()),
1037 codegen_(codegen) {}
1038
1039#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
Alexandre Rames3e69f162014-12-10 10:36:50 +00001040 /* No unimplemented IR. */
Alexandre Rames5319def2014-10-23 10:03:10 +01001041
1042#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
1043
1044enum UnimplementedInstructionBreakCode {
Alexandre Rames67555f72014-11-18 10:55:16 +00001045 // Using a base helps identify when we hit such breakpoints.
1046 UnimplementedInstructionBreakCodeBaseCode = 0x900,
Alexandre Rames5319def2014-10-23 10:03:10 +01001047#define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name),
1048 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION)
1049#undef ENUM_UNIMPLEMENTED_INSTRUCTION
1050};
1051
1052#define DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS(name) \
1053 void InstructionCodeGeneratorARM64::Visit##name(H##name* instr) { \
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001054 UNUSED(instr); \
Alexandre Rames5319def2014-10-23 10:03:10 +01001055 __ Brk(UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name)); \
1056 } \
1057 void LocationsBuilderARM64::Visit##name(H##name* instr) { \
1058 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); \
1059 locations->SetOut(Location::Any()); \
1060 }
1061 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS)
1062#undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS
1063
1064#undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE
Alexandre Rames67555f72014-11-18 10:55:16 +00001065#undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION
Alexandre Rames5319def2014-10-23 10:03:10 +01001066
Alexandre Rames67555f72014-11-18 10:55:16 +00001067void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001068 DCHECK_EQ(instr->InputCount(), 2U);
1069 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1070 Primitive::Type type = instr->GetResultType();
1071 switch (type) {
1072 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001073 case Primitive::kPrimLong:
Alexandre Rames5319def2014-10-23 10:03:10 +01001074 locations->SetInAt(0, Location::RequiresRegister());
1075 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001076 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001077 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001078
1079 case Primitive::kPrimFloat:
1080 case Primitive::kPrimDouble:
1081 locations->SetInAt(0, Location::RequiresFpuRegister());
1082 locations->SetInAt(1, Location::RequiresFpuRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00001083 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001084 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001085
Alexandre Rames5319def2014-10-23 10:03:10 +01001086 default:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001087 LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +01001088 }
1089}
1090
Alexandre Rames67555f72014-11-18 10:55:16 +00001091void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001092 Primitive::Type type = instr->GetType();
Alexandre Rames5319def2014-10-23 10:03:10 +01001093
1094 switch (type) {
1095 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001096 case Primitive::kPrimLong: {
1097 Register dst = OutputRegister(instr);
1098 Register lhs = InputRegisterAt(instr, 0);
1099 Operand rhs = InputOperandAt(instr, 1);
Alexandre Rames5319def2014-10-23 10:03:10 +01001100 if (instr->IsAdd()) {
1101 __ Add(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001102 } else if (instr->IsAnd()) {
1103 __ And(dst, lhs, rhs);
1104 } else if (instr->IsOr()) {
1105 __ Orr(dst, lhs, rhs);
1106 } else if (instr->IsSub()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001107 __ Sub(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001108 } else {
1109 DCHECK(instr->IsXor());
1110 __ Eor(dst, lhs, rhs);
Alexandre Rames5319def2014-10-23 10:03:10 +01001111 }
1112 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001113 }
1114 case Primitive::kPrimFloat:
1115 case Primitive::kPrimDouble: {
1116 FPRegister dst = OutputFPRegister(instr);
1117 FPRegister lhs = InputFPRegisterAt(instr, 0);
1118 FPRegister rhs = InputFPRegisterAt(instr, 1);
1119 if (instr->IsAdd()) {
1120 __ Fadd(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001121 } else if (instr->IsSub()) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001122 __ Fsub(dst, lhs, rhs);
Alexandre Rames67555f72014-11-18 10:55:16 +00001123 } else {
1124 LOG(FATAL) << "Unexpected floating-point binary operation";
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001125 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001126 break;
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001127 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001128 default:
Alexandre Rames67555f72014-11-18 10:55:16 +00001129 LOG(FATAL) << "Unexpected binary operation type " << type;
Alexandre Rames5319def2014-10-23 10:03:10 +01001130 }
1131}
1132
Serban Constantinescu02164b32014-11-13 14:05:07 +00001133void LocationsBuilderARM64::HandleShift(HBinaryOperation* instr) {
1134 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
1135
1136 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1137 Primitive::Type type = instr->GetResultType();
1138 switch (type) {
1139 case Primitive::kPrimInt:
1140 case Primitive::kPrimLong: {
1141 locations->SetInAt(0, Location::RequiresRegister());
1142 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1143 locations->SetOut(Location::RequiresRegister());
1144 break;
1145 }
1146 default:
1147 LOG(FATAL) << "Unexpected shift type " << type;
1148 }
1149}
1150
1151void InstructionCodeGeneratorARM64::HandleShift(HBinaryOperation* instr) {
1152 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
1153
1154 Primitive::Type type = instr->GetType();
1155 switch (type) {
1156 case Primitive::kPrimInt:
1157 case Primitive::kPrimLong: {
1158 Register dst = OutputRegister(instr);
1159 Register lhs = InputRegisterAt(instr, 0);
1160 Operand rhs = InputOperandAt(instr, 1);
1161 if (rhs.IsImmediate()) {
1162 uint32_t shift_value = (type == Primitive::kPrimInt)
1163 ? static_cast<uint32_t>(rhs.immediate() & kMaxIntShiftValue)
1164 : static_cast<uint32_t>(rhs.immediate() & kMaxLongShiftValue);
1165 if (instr->IsShl()) {
1166 __ Lsl(dst, lhs, shift_value);
1167 } else if (instr->IsShr()) {
1168 __ Asr(dst, lhs, shift_value);
1169 } else {
1170 __ Lsr(dst, lhs, shift_value);
1171 }
1172 } else {
1173 Register rhs_reg = dst.IsX() ? rhs.reg().X() : rhs.reg().W();
1174
1175 if (instr->IsShl()) {
1176 __ Lsl(dst, lhs, rhs_reg);
1177 } else if (instr->IsShr()) {
1178 __ Asr(dst, lhs, rhs_reg);
1179 } else {
1180 __ Lsr(dst, lhs, rhs_reg);
1181 }
1182 }
1183 break;
1184 }
1185 default:
1186 LOG(FATAL) << "Unexpected shift operation type " << type;
1187 }
1188}
1189
Alexandre Rames5319def2014-10-23 10:03:10 +01001190void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001191 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001192}
1193
1194void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001195 HandleBinaryOp(instruction);
1196}
1197
1198void LocationsBuilderARM64::VisitAnd(HAnd* instruction) {
1199 HandleBinaryOp(instruction);
1200}
1201
1202void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) {
1203 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001204}
1205
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001206void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
1207 LocationSummary* locations =
1208 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1209 locations->SetInAt(0, Location::RequiresRegister());
1210 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1211 locations->SetOut(Location::RequiresRegister());
1212}
1213
1214void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
1215 LocationSummary* locations = instruction->GetLocations();
1216 Primitive::Type type = instruction->GetType();
1217 Register obj = InputRegisterAt(instruction, 0);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001218 Location index = locations->InAt(1);
1219 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001220 MemOperand source = HeapOperand(obj);
Alexandre Rames67555f72014-11-18 10:55:16 +00001221 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001222
1223 if (index.IsConstant()) {
1224 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001225 source = HeapOperand(obj, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001226 } else {
1227 Register temp = temps.AcquireSameSizeAs(obj);
1228 Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
1229 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type)));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001230 source = HeapOperand(temp, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001231 }
1232
Alexandre Rames67555f72014-11-18 10:55:16 +00001233 codegen_->Load(type, OutputCPURegister(instruction), source);
Calin Juravle77520bc2015-01-12 18:45:46 +00001234 codegen_->MaybeRecordImplicitNullCheck(instruction);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001235}
1236
Alexandre Rames5319def2014-10-23 10:03:10 +01001237void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
1238 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1239 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001240 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001241}
1242
1243void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
1244 __ Ldr(OutputRegister(instruction),
1245 HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset()));
Calin Juravle77520bc2015-01-12 18:45:46 +00001246 codegen_->MaybeRecordImplicitNullCheck(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01001247}
1248
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001249void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
1250 Primitive::Type value_type = instruction->GetComponentType();
1251 bool is_object = value_type == Primitive::kPrimNot;
1252 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1253 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
1254 if (is_object) {
1255 InvokeRuntimeCallingConvention calling_convention;
1256 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
1257 locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
1258 locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
1259 } else {
1260 locations->SetInAt(0, Location::RequiresRegister());
1261 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1262 locations->SetInAt(2, Location::RequiresRegister());
1263 }
1264}
1265
1266void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
1267 Primitive::Type value_type = instruction->GetComponentType();
1268 if (value_type == Primitive::kPrimNot) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001269 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08001270 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001271 } else {
1272 LocationSummary* locations = instruction->GetLocations();
1273 Register obj = InputRegisterAt(instruction, 0);
Alexandre Rames67555f72014-11-18 10:55:16 +00001274 CPURegister value = InputCPURegisterAt(instruction, 2);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001275 Location index = locations->InAt(1);
1276 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001277 MemOperand destination = HeapOperand(obj);
Alexandre Rames67555f72014-11-18 10:55:16 +00001278 UseScratchRegisterScope temps(GetVIXLAssembler());
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001279
1280 if (index.IsConstant()) {
1281 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001282 destination = HeapOperand(obj, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001283 } else {
1284 Register temp = temps.AcquireSameSizeAs(obj);
1285 Register index_reg = InputRegisterAt(instruction, 1);
1286 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type)));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001287 destination = HeapOperand(temp, offset);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001288 }
1289
1290 codegen_->Store(value_type, value, destination);
Calin Juravle77520bc2015-01-12 18:45:46 +00001291 codegen_->MaybeRecordImplicitNullCheck(instruction);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001292 }
1293}
1294
Alexandre Rames67555f72014-11-18 10:55:16 +00001295void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1296 LocationSummary* locations =
1297 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1298 locations->SetInAt(0, Location::RequiresRegister());
1299 locations->SetInAt(1, Location::RequiresRegister());
1300 if (instruction->HasUses()) {
1301 locations->SetOut(Location::SameAsFirstInput());
1302 }
1303}
1304
1305void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
Alexandre Rames3e69f162014-12-10 10:36:50 +00001306 LocationSummary* locations = instruction->GetLocations();
1307 BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(
1308 instruction, locations->InAt(0), locations->InAt(1));
Alexandre Rames67555f72014-11-18 10:55:16 +00001309 codegen_->AddSlowPath(slow_path);
1310
1311 __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
1312 __ B(slow_path->GetEntryLabel(), hs);
1313}
1314
1315void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
1316 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1317 instruction, LocationSummary::kCallOnSlowPath);
1318 locations->SetInAt(0, Location::RequiresRegister());
1319 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Rames3e69f162014-12-10 10:36:50 +00001320 locations->AddTemp(Location::RequiresRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00001321}
1322
1323void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
Alexandre Rames3e69f162014-12-10 10:36:50 +00001324 LocationSummary* locations = instruction->GetLocations();
Alexandre Rames67555f72014-11-18 10:55:16 +00001325 Register obj = InputRegisterAt(instruction, 0);;
1326 Register cls = InputRegisterAt(instruction, 1);;
Alexandre Rames3e69f162014-12-10 10:36:50 +00001327 Register obj_cls = WRegisterFrom(instruction->GetLocations()->GetTemp(0));
Alexandre Rames67555f72014-11-18 10:55:16 +00001328
Alexandre Rames3e69f162014-12-10 10:36:50 +00001329 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(
1330 instruction, locations->InAt(1), LocationFrom(obj_cls), instruction->GetDexPc());
Alexandre Rames67555f72014-11-18 10:55:16 +00001331 codegen_->AddSlowPath(slow_path);
1332
1333 // TODO: avoid this check if we know obj is not null.
1334 __ Cbz(obj, slow_path->GetExitLabel());
1335 // Compare the class of `obj` with `cls`.
Alexandre Rames3e69f162014-12-10 10:36:50 +00001336 __ Ldr(obj_cls, HeapOperand(obj, mirror::Object::ClassOffset()));
1337 __ Cmp(obj_cls, cls);
Alexandre Rames67555f72014-11-18 10:55:16 +00001338 __ B(ne, slow_path->GetEntryLabel());
1339 __ Bind(slow_path->GetExitLabel());
1340}
1341
1342void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) {
1343 LocationSummary* locations =
1344 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
1345 locations->SetInAt(0, Location::RequiresRegister());
1346 if (check->HasUses()) {
1347 locations->SetOut(Location::SameAsFirstInput());
1348 }
1349}
1350
1351void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) {
1352 // We assume the class is not null.
1353 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
1354 check->GetLoadClass(), check, check->GetDexPc(), true);
1355 codegen_->AddSlowPath(slow_path);
1356 GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
1357}
1358
Serban Constantinescu02164b32014-11-13 14:05:07 +00001359void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001360 LocationSummary* locations =
Serban Constantinescu02164b32014-11-13 14:05:07 +00001361 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
1362 Primitive::Type in_type = compare->InputAt(0)->GetType();
Alexandre Rames5319def2014-10-23 10:03:10 +01001363 switch (in_type) {
1364 case Primitive::kPrimLong: {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001365 locations->SetInAt(0, Location::RequiresRegister());
1366 locations->SetInAt(1, Location::RegisterOrConstant(compare->InputAt(1)));
1367 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1368 break;
1369 }
1370 case Primitive::kPrimFloat:
1371 case Primitive::kPrimDouble: {
1372 locations->SetInAt(0, Location::RequiresFpuRegister());
1373 locations->SetInAt(1, Location::RequiresFpuRegister());
1374 locations->SetOut(Location::RequiresRegister());
1375 break;
1376 }
1377 default:
1378 LOG(FATAL) << "Unexpected type for compare operation " << in_type;
1379 }
1380}
1381
1382void InstructionCodeGeneratorARM64::VisitCompare(HCompare* compare) {
1383 Primitive::Type in_type = compare->InputAt(0)->GetType();
1384
1385 // 0 if: left == right
1386 // 1 if: left > right
1387 // -1 if: left < right
1388 switch (in_type) {
1389 case Primitive::kPrimLong: {
1390 Register result = OutputRegister(compare);
1391 Register left = InputRegisterAt(compare, 0);
1392 Operand right = InputOperandAt(compare, 1);
1393
1394 __ Cmp(left, right);
1395 __ Cset(result, ne);
1396 __ Cneg(result, result, lt);
1397 break;
1398 }
1399 case Primitive::kPrimFloat:
1400 case Primitive::kPrimDouble: {
1401 Register result = OutputRegister(compare);
1402 FPRegister left = InputFPRegisterAt(compare, 0);
1403 FPRegister right = InputFPRegisterAt(compare, 1);
1404
1405 __ Fcmp(left, right);
1406 if (compare->IsGtBias()) {
1407 __ Cset(result, ne);
1408 } else {
1409 __ Csetm(result, ne);
1410 }
1411 __ Cneg(result, result, compare->IsGtBias() ? mi : gt);
Alexandre Rames5319def2014-10-23 10:03:10 +01001412 break;
1413 }
1414 default:
1415 LOG(FATAL) << "Unimplemented compare type " << in_type;
1416 }
1417}
1418
1419void LocationsBuilderARM64::VisitCondition(HCondition* instruction) {
1420 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1421 locations->SetInAt(0, Location::RequiresRegister());
1422 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1423 if (instruction->NeedsMaterialization()) {
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001424 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001425 }
1426}
1427
1428void InstructionCodeGeneratorARM64::VisitCondition(HCondition* instruction) {
1429 if (!instruction->NeedsMaterialization()) {
1430 return;
1431 }
1432
1433 LocationSummary* locations = instruction->GetLocations();
1434 Register lhs = InputRegisterAt(instruction, 0);
1435 Operand rhs = InputOperandAt(instruction, 1);
1436 Register res = RegisterFrom(locations->Out(), instruction->GetType());
1437 Condition cond = ARM64Condition(instruction->GetCondition());
1438
1439 __ Cmp(lhs, rhs);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001440 __ Cset(res, cond);
Alexandre Rames5319def2014-10-23 10:03:10 +01001441}
1442
1443#define FOR_EACH_CONDITION_INSTRUCTION(M) \
1444 M(Equal) \
1445 M(NotEqual) \
1446 M(LessThan) \
1447 M(LessThanOrEqual) \
1448 M(GreaterThan) \
1449 M(GreaterThanOrEqual)
1450#define DEFINE_CONDITION_VISITORS(Name) \
1451void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } \
1452void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }
1453FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
Alexandre Rames67555f72014-11-18 10:55:16 +00001454#undef DEFINE_CONDITION_VISITORS
Alexandre Rames5319def2014-10-23 10:03:10 +01001455#undef FOR_EACH_CONDITION_INSTRUCTION
1456
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001457void LocationsBuilderARM64::VisitDiv(HDiv* div) {
1458 LocationSummary* locations =
1459 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
1460 switch (div->GetResultType()) {
1461 case Primitive::kPrimInt:
1462 case Primitive::kPrimLong:
1463 locations->SetInAt(0, Location::RequiresRegister());
1464 locations->SetInAt(1, Location::RequiresRegister());
1465 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1466 break;
1467
1468 case Primitive::kPrimFloat:
1469 case Primitive::kPrimDouble:
1470 locations->SetInAt(0, Location::RequiresFpuRegister());
1471 locations->SetInAt(1, Location::RequiresFpuRegister());
1472 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1473 break;
1474
1475 default:
1476 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1477 }
1478}
1479
1480void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
1481 Primitive::Type type = div->GetResultType();
1482 switch (type) {
1483 case Primitive::kPrimInt:
1484 case Primitive::kPrimLong:
1485 __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
1486 break;
1487
1488 case Primitive::kPrimFloat:
1489 case Primitive::kPrimDouble:
1490 __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
1491 break;
1492
1493 default:
1494 LOG(FATAL) << "Unexpected div type " << type;
1495 }
1496}
1497
Alexandre Rames67555f72014-11-18 10:55:16 +00001498void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1499 LocationSummary* locations =
1500 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1501 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
1502 if (instruction->HasUses()) {
1503 locations->SetOut(Location::SameAsFirstInput());
1504 }
1505}
1506
1507void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1508 SlowPathCodeARM64* slow_path =
1509 new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction);
1510 codegen_->AddSlowPath(slow_path);
1511 Location value = instruction->GetLocations()->InAt(0);
1512
Alexandre Rames3e69f162014-12-10 10:36:50 +00001513 Primitive::Type type = instruction->GetType();
1514
1515 if ((type != Primitive::kPrimInt) && (type != Primitive::kPrimLong)) {
1516 LOG(FATAL) << "Unexpected type " << type << "for DivZeroCheck.";
1517 return;
1518 }
1519
Alexandre Rames67555f72014-11-18 10:55:16 +00001520 if (value.IsConstant()) {
1521 int64_t divisor = Int64ConstantFrom(value);
1522 if (divisor == 0) {
1523 __ B(slow_path->GetEntryLabel());
1524 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +00001525 // A division by a non-null constant is valid. We don't need to perform
1526 // any check, so simply fall through.
Alexandre Rames67555f72014-11-18 10:55:16 +00001527 }
1528 } else {
1529 __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
1530 }
1531}
1532
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001533void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1534 LocationSummary* locations =
1535 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1536 locations->SetOut(Location::ConstantLocation(constant));
1537}
1538
1539void InstructionCodeGeneratorARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1540 UNUSED(constant);
1541 // Will be generated at use site.
1542}
1543
Alexandre Rames5319def2014-10-23 10:03:10 +01001544void LocationsBuilderARM64::VisitExit(HExit* exit) {
1545 exit->SetLocations(nullptr);
1546}
1547
1548void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001549 UNUSED(exit);
Alexandre Rames5319def2014-10-23 10:03:10 +01001550 if (kIsDebugBuild) {
1551 down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable");
Alexandre Rames67555f72014-11-18 10:55:16 +00001552 __ Brk(__LINE__); // TODO: Introduce special markers for such code locations.
Alexandre Rames5319def2014-10-23 10:03:10 +01001553 }
1554}
1555
Alexandre Ramesa89086e2014-11-07 17:13:25 +00001556void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) {
1557 LocationSummary* locations =
1558 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1559 locations->SetOut(Location::ConstantLocation(constant));
1560}
1561
1562void InstructionCodeGeneratorARM64::VisitFloatConstant(HFloatConstant* constant) {
1563 UNUSED(constant);
1564 // Will be generated at use site.
1565}
1566
Alexandre Rames5319def2014-10-23 10:03:10 +01001567void LocationsBuilderARM64::VisitGoto(HGoto* got) {
1568 got->SetLocations(nullptr);
1569}
1570
1571void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
1572 HBasicBlock* successor = got->GetSuccessor();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001573 DCHECK(!successor->IsExitBlock());
1574 HBasicBlock* block = got->GetBlock();
1575 HInstruction* previous = got->GetPrevious();
1576 HLoopInformation* info = block->GetLoopInformation();
1577
1578 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
1579 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1580 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1581 return;
1582 }
1583 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1584 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1585 }
1586 if (!codegen_->GoesToNextBlock(block, successor)) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001587 __ B(codegen_->GetLabelOf(successor));
1588 }
1589}
1590
1591void LocationsBuilderARM64::VisitIf(HIf* if_instr) {
1592 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1593 HInstruction* cond = if_instr->InputAt(0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001594 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001595 locations->SetInAt(0, Location::RequiresRegister());
1596 }
1597}
1598
1599void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) {
1600 HInstruction* cond = if_instr->InputAt(0);
Alexandre Rames5319def2014-10-23 10:03:10 +01001601 HCondition* condition = cond->AsCondition();
1602 vixl::Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1603 vixl::Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1604
Serban Constantinescu02164b32014-11-13 14:05:07 +00001605 if (cond->IsIntConstant()) {
1606 int32_t cond_value = cond->AsIntConstant()->GetValue();
1607 if (cond_value == 1) {
1608 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
1609 __ B(true_target);
1610 }
1611 return;
1612 } else {
1613 DCHECK_EQ(cond_value, 0);
1614 }
1615 } else if (!cond->IsCondition() || condition->NeedsMaterialization()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001616 // The condition instruction has been materialized, compare the output to 0.
1617 Location cond_val = if_instr->GetLocations()->InAt(0);
1618 DCHECK(cond_val.IsRegister());
1619 __ Cbnz(InputRegisterAt(if_instr, 0), true_target);
Alexandre Rames5319def2014-10-23 10:03:10 +01001620 } else {
1621 // The condition instruction has not been materialized, use its inputs as
1622 // the comparison and its condition as the branch condition.
1623 Register lhs = InputRegisterAt(condition, 0);
1624 Operand rhs = InputOperandAt(condition, 1);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001625 Condition arm64_cond = ARM64Condition(condition->GetCondition());
1626 if ((arm64_cond == eq || arm64_cond == ne) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
1627 if (arm64_cond == eq) {
Alexandre Rames5319def2014-10-23 10:03:10 +01001628 __ Cbz(lhs, true_target);
1629 } else {
1630 __ Cbnz(lhs, true_target);
1631 }
1632 } else {
1633 __ Cmp(lhs, rhs);
Andreas Gampe277ccbd2014-11-03 21:36:10 -08001634 __ B(arm64_cond, true_target);
Alexandre Rames5319def2014-10-23 10:03:10 +01001635 }
1636 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001637 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
1638 __ B(false_target);
1639 }
1640}
1641
1642void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001643 LocationSummary* locations =
1644 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Alexandre Rames5319def2014-10-23 10:03:10 +01001645 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00001646 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01001647}
1648
1649void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001650 MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset());
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001651
1652 if (instruction->IsVolatile()) {
1653 if (kUseAcquireRelease) {
Calin Juravle77520bc2015-01-12 18:45:46 +00001654 // NB: LoadAcquire will record the pc info if needed.
1655 codegen_->LoadAcquire(instruction, OutputCPURegister(instruction), field);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001656 } else {
1657 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
Calin Juravle77520bc2015-01-12 18:45:46 +00001658 codegen_->MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001659 // For IRIW sequential consistency kLoadAny is not sufficient.
1660 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
1661 }
1662 } else {
1663 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
Calin Juravle77520bc2015-01-12 18:45:46 +00001664 codegen_->MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001665 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001666}
1667
1668void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001669 LocationSummary* locations =
1670 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Alexandre Rames5319def2014-10-23 10:03:10 +01001671 locations->SetInAt(0, Location::RequiresRegister());
1672 locations->SetInAt(1, Location::RequiresRegister());
1673}
1674
1675void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Alexandre Ramesfc19de82014-11-07 17:13:31 +00001676 Register obj = InputRegisterAt(instruction, 0);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001677 CPURegister value = InputCPURegisterAt(instruction, 1);
1678 Offset offset = instruction->GetFieldOffset();
1679 Primitive::Type field_type = instruction->GetFieldType();
1680
1681 if (instruction->IsVolatile()) {
1682 if (kUseAcquireRelease) {
1683 codegen_->StoreRelease(field_type, value, HeapOperand(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001684 codegen_->MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001685 } else {
1686 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
1687 codegen_->Store(field_type, value, HeapOperand(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001688 codegen_->MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001689 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
1690 }
1691 } else {
1692 codegen_->Store(field_type, value, HeapOperand(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00001693 codegen_->MaybeRecordImplicitNullCheck(instruction);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00001694 }
1695
1696 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Alexandre Rames67555f72014-11-18 10:55:16 +00001697 codegen_->MarkGCCard(obj, Register(value));
Alexandre Rames5319def2014-10-23 10:03:10 +01001698 }
1699}
1700
Alexandre Rames67555f72014-11-18 10:55:16 +00001701void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
1702 LocationSummary::CallKind call_kind =
1703 instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
1704 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
1705 locations->SetInAt(0, Location::RequiresRegister());
1706 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00001707 // The output does overlap inputs.
1708 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Alexandre Rames67555f72014-11-18 10:55:16 +00001709}
1710
1711void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
1712 LocationSummary* locations = instruction->GetLocations();
1713 Register obj = InputRegisterAt(instruction, 0);;
1714 Register cls = InputRegisterAt(instruction, 1);;
1715 Register out = OutputRegister(instruction);
1716
1717 vixl::Label done;
1718
1719 // Return 0 if `obj` is null.
1720 // TODO: Avoid this check if we know `obj` is not null.
1721 __ Mov(out, 0);
1722 __ Cbz(obj, &done);
1723
1724 // Compare the class of `obj` with `cls`.
Serban Constantinescu02164b32014-11-13 14:05:07 +00001725 __ Ldr(out, HeapOperand(obj, mirror::Object::ClassOffset()));
Alexandre Rames67555f72014-11-18 10:55:16 +00001726 __ Cmp(out, cls);
1727 if (instruction->IsClassFinal()) {
1728 // Classes must be equal for the instanceof to succeed.
1729 __ Cset(out, eq);
1730 } else {
1731 // If the classes are not equal, we go into a slow path.
1732 DCHECK(locations->OnlyCallsOnSlowPath());
1733 SlowPathCodeARM64* slow_path =
Alexandre Rames3e69f162014-12-10 10:36:50 +00001734 new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(
1735 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Alexandre Rames67555f72014-11-18 10:55:16 +00001736 codegen_->AddSlowPath(slow_path);
1737 __ B(ne, slow_path->GetEntryLabel());
1738 __ Mov(out, 1);
1739 __ Bind(slow_path->GetExitLabel());
1740 }
1741
1742 __ Bind(&done);
1743}
1744
Alexandre Rames5319def2014-10-23 10:03:10 +01001745void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
1746 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1747 locations->SetOut(Location::ConstantLocation(constant));
1748}
1749
1750void InstructionCodeGeneratorARM64::VisitIntConstant(HIntConstant* constant) {
1751 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001752 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001753}
1754
Alexandre Rames5319def2014-10-23 10:03:10 +01001755void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
1756 LocationSummary* locations =
1757 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
1758 locations->AddTemp(LocationFrom(x0));
1759
1760 InvokeDexCallingConventionVisitor calling_convention_visitor;
1761 for (size_t i = 0; i < invoke->InputCount(); i++) {
1762 HInstruction* input = invoke->InputAt(i);
1763 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1764 }
1765
1766 Primitive::Type return_type = invoke->GetType();
1767 if (return_type != Primitive::kPrimVoid) {
1768 locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type));
1769 }
1770}
1771
Alexandre Rames67555f72014-11-18 10:55:16 +00001772void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1773 HandleInvoke(invoke);
1774}
1775
1776void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1777 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1778 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1779 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1780 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1781 Location receiver = invoke->GetLocations()->InAt(0);
1782 Offset class_offset = mirror::Object::ClassOffset();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001783 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
Alexandre Rames67555f72014-11-18 10:55:16 +00001784
1785 // The register ip1 is required to be used for the hidden argument in
1786 // art_quick_imt_conflict_trampoline, so prevent VIXL from using it.
1787 UseScratchRegisterScope scratch_scope(GetVIXLAssembler());
1788 scratch_scope.Exclude(ip1);
1789 __ Mov(ip1, invoke->GetDexMethodIndex());
1790
1791 // temp = object->GetClass();
1792 if (receiver.IsStackSlot()) {
1793 __ Ldr(temp, StackOperandFrom(receiver));
1794 __ Ldr(temp, HeapOperand(temp, class_offset));
1795 } else {
1796 __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
1797 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001798 codegen_->MaybeRecordImplicitNullCheck(invoke);
Alexandre Rames67555f72014-11-18 10:55:16 +00001799 // temp = temp->GetImtEntryAt(method_offset);
1800 __ Ldr(temp, HeapOperand(temp, method_offset));
1801 // lr = temp->GetEntryPoint();
1802 __ Ldr(lr, HeapOperand(temp, entry_point));
1803 // lr();
1804 __ Blr(lr);
1805 DCHECK(!codegen_->IsLeafMethod());
1806 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1807}
1808
1809void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe878d58c2015-01-15 23:24:00 -08001810 IntrinsicLocationsBuilderARM64 intrinsic(GetGraph()->GetArena());
1811 if (intrinsic.TryDispatch(invoke)) {
1812 return;
1813 }
1814
Alexandre Rames67555f72014-11-18 10:55:16 +00001815 HandleInvoke(invoke);
1816}
1817
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001818void LocationsBuilderARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Andreas Gampe878d58c2015-01-15 23:24:00 -08001819 IntrinsicLocationsBuilderARM64 intrinsic(GetGraph()->GetArena());
1820 if (intrinsic.TryDispatch(invoke)) {
1821 return;
1822 }
1823
Alexandre Rames67555f72014-11-18 10:55:16 +00001824 HandleInvoke(invoke);
1825}
1826
Andreas Gampe878d58c2015-01-15 23:24:00 -08001827static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM64* codegen) {
1828 if (invoke->GetLocations()->Intrinsified()) {
1829 IntrinsicCodeGeneratorARM64 intrinsic(codegen);
1830 intrinsic.Dispatch(invoke);
1831 return true;
1832 }
1833 return false;
1834}
1835
1836void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) {
1837 // Make sure that ArtMethod* is passed in kArtMethodRegister as per the calling convention.
1838 DCHECK(temp.Is(kArtMethodRegister));
Alexandre Rames5319def2014-10-23 10:03:10 +01001839 size_t index_in_cache = mirror::Array::DataOffset(kHeapRefSize).SizeValue() +
Andreas Gampe878d58c2015-01-15 23:24:00 -08001840 invoke->GetDexMethodIndex() * kHeapRefSize;
Alexandre Rames5319def2014-10-23 10:03:10 +01001841
1842 // TODO: Implement all kinds of calls:
1843 // 1) boot -> boot
1844 // 2) app -> boot
1845 // 3) app -> app
1846 //
1847 // Currently we implement the app -> app logic, which looks up in the resolve cache.
1848
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001849 if (!invoke->IsRecursive()) {
1850 // temp = method;
1851 LoadCurrentMethod(temp);
1852 // temp = temp->dex_cache_resolved_methods_;
1853 __ Ldr(temp, HeapOperand(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset()));
1854 // temp = temp[index_in_cache];
1855 __ Ldr(temp, HeapOperand(temp, index_in_cache));
1856 // lr = temp->entry_point_from_quick_compiled_code_;
1857 __ Ldr(lr, HeapOperand(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
1858 kArm64WordSize)));
1859 // lr();
1860 __ Blr(lr);
1861 } else {
1862 __ Bl(&frame_entry_label_);
1863 }
Alexandre Rames5319def2014-10-23 10:03:10 +01001864
Andreas Gampe878d58c2015-01-15 23:24:00 -08001865 RecordPcInfo(invoke, invoke->GetDexPc());
1866 DCHECK(!IsLeafMethod());
1867}
1868
1869void InstructionCodeGeneratorARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
1870 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1871 return;
1872 }
1873
1874 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
1875 codegen_->GenerateStaticOrDirectCall(invoke, temp);
Alexandre Rames5319def2014-10-23 10:03:10 +01001876}
1877
1878void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe878d58c2015-01-15 23:24:00 -08001879 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1880 return;
1881 }
1882
Alexandre Rames5319def2014-10-23 10:03:10 +01001883 LocationSummary* locations = invoke->GetLocations();
1884 Location receiver = locations->InAt(0);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001885 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
Alexandre Rames5319def2014-10-23 10:03:10 +01001886 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
1887 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1888 Offset class_offset = mirror::Object::ClassOffset();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001889 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
Alexandre Rames5319def2014-10-23 10:03:10 +01001890
1891 // temp = object->GetClass();
1892 if (receiver.IsStackSlot()) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00001893 __ Ldr(temp, MemOperand(sp, receiver.GetStackIndex()));
1894 __ Ldr(temp, HeapOperand(temp, class_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001895 } else {
1896 DCHECK(receiver.IsRegister());
Serban Constantinescu02164b32014-11-13 14:05:07 +00001897 __ Ldr(temp, HeapOperandFrom(receiver, class_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001898 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001899 codegen_->MaybeRecordImplicitNullCheck(invoke);
Alexandre Rames5319def2014-10-23 10:03:10 +01001900 // temp = temp->GetMethodAt(method_offset);
Serban Constantinescu02164b32014-11-13 14:05:07 +00001901 __ Ldr(temp, HeapOperand(temp, method_offset));
Alexandre Rames5319def2014-10-23 10:03:10 +01001902 // lr = temp->GetEntryPoint();
Serban Constantinescu02164b32014-11-13 14:05:07 +00001903 __ Ldr(lr, HeapOperand(temp, entry_point.SizeValue()));
Alexandre Rames5319def2014-10-23 10:03:10 +01001904 // lr();
1905 __ Blr(lr);
1906 DCHECK(!codegen_->IsLeafMethod());
1907 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1908}
1909
Alexandre Rames67555f72014-11-18 10:55:16 +00001910void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
1911 LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
1912 : LocationSummary::kNoCall;
1913 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
1914 locations->SetOut(Location::RequiresRegister());
1915}
1916
1917void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
1918 Register out = OutputRegister(cls);
1919 if (cls->IsReferrersClass()) {
1920 DCHECK(!cls->CanCallRuntime());
1921 DCHECK(!cls->MustGenerateClinitCheck());
1922 codegen_->LoadCurrentMethod(out);
1923 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
1924 } else {
1925 DCHECK(cls->CanCallRuntime());
1926 codegen_->LoadCurrentMethod(out);
1927 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset()));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001928 __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Alexandre Rames67555f72014-11-18 10:55:16 +00001929
1930 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
1931 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
1932 codegen_->AddSlowPath(slow_path);
1933 __ Cbz(out, slow_path->GetEntryLabel());
1934 if (cls->MustGenerateClinitCheck()) {
1935 GenerateClassInitializationCheck(slow_path, out);
1936 } else {
1937 __ Bind(slow_path->GetExitLabel());
1938 }
1939 }
1940}
1941
1942void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
1943 LocationSummary* locations =
1944 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
1945 locations->SetOut(Location::RequiresRegister());
1946}
1947
1948void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
1949 MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
1950 __ Ldr(OutputRegister(instruction), exception);
1951 __ Str(wzr, exception);
1952}
1953
Alexandre Rames5319def2014-10-23 10:03:10 +01001954void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
1955 load->SetLocations(nullptr);
1956}
1957
1958void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) {
1959 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001960 UNUSED(load);
Alexandre Rames5319def2014-10-23 10:03:10 +01001961}
1962
Alexandre Rames67555f72014-11-18 10:55:16 +00001963void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
1964 LocationSummary* locations =
1965 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
1966 locations->SetOut(Location::RequiresRegister());
1967}
1968
1969void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
1970 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
1971 codegen_->AddSlowPath(slow_path);
1972
1973 Register out = OutputRegister(load);
1974 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08001975 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset()));
1976 __ Ldr(out, HeapOperand(out, mirror::Class::DexCacheStringsOffset()));
Serban Constantinescu02164b32014-11-13 14:05:07 +00001977 __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Alexandre Rames67555f72014-11-18 10:55:16 +00001978 __ Cbz(out, slow_path->GetEntryLabel());
1979 __ Bind(slow_path->GetExitLabel());
1980}
1981
Alexandre Rames5319def2014-10-23 10:03:10 +01001982void LocationsBuilderARM64::VisitLocal(HLocal* local) {
1983 local->SetLocations(nullptr);
1984}
1985
1986void InstructionCodeGeneratorARM64::VisitLocal(HLocal* local) {
1987 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
1988}
1989
1990void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
1991 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1992 locations->SetOut(Location::ConstantLocation(constant));
1993}
1994
1995void InstructionCodeGeneratorARM64::VisitLongConstant(HLongConstant* constant) {
1996 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001997 UNUSED(constant);
Alexandre Rames5319def2014-10-23 10:03:10 +01001998}
1999
Alexandre Rames67555f72014-11-18 10:55:16 +00002000void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
2001 LocationSummary* locations =
2002 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2003 InvokeRuntimeCallingConvention calling_convention;
2004 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2005}
2006
2007void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
2008 codegen_->InvokeRuntime(instruction->IsEnter()
2009 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
2010 instruction,
2011 instruction->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002012 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
Alexandre Rames67555f72014-11-18 10:55:16 +00002013}
2014
Alexandre Rames42d641b2014-10-27 14:00:51 +00002015void LocationsBuilderARM64::VisitMul(HMul* mul) {
2016 LocationSummary* locations =
2017 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2018 switch (mul->GetResultType()) {
2019 case Primitive::kPrimInt:
2020 case Primitive::kPrimLong:
2021 locations->SetInAt(0, Location::RequiresRegister());
2022 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00002023 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00002024 break;
2025
2026 case Primitive::kPrimFloat:
2027 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002028 locations->SetInAt(0, Location::RequiresFpuRegister());
2029 locations->SetInAt(1, Location::RequiresFpuRegister());
Alexandre Rames67555f72014-11-18 10:55:16 +00002030 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Rames42d641b2014-10-27 14:00:51 +00002031 break;
2032
2033 default:
2034 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2035 }
2036}
2037
2038void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) {
2039 switch (mul->GetResultType()) {
2040 case Primitive::kPrimInt:
2041 case Primitive::kPrimLong:
2042 __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
2043 break;
2044
2045 case Primitive::kPrimFloat:
2046 case Primitive::kPrimDouble:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002047 __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1));
Alexandre Rames42d641b2014-10-27 14:00:51 +00002048 break;
2049
2050 default:
2051 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2052 }
2053}
2054
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002055void LocationsBuilderARM64::VisitNeg(HNeg* neg) {
2056 LocationSummary* locations =
2057 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2058 switch (neg->GetResultType()) {
2059 case Primitive::kPrimInt:
Alexandre Rames67555f72014-11-18 10:55:16 +00002060 case Primitive::kPrimLong:
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002061 locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0)));
Alexandre Rames67555f72014-11-18 10:55:16 +00002062 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002063 break;
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002064
2065 case Primitive::kPrimFloat:
2066 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +00002067 locations->SetInAt(0, Location::RequiresFpuRegister());
2068 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002069 break;
2070
2071 default:
2072 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2073 }
2074}
2075
2076void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
2077 switch (neg->GetResultType()) {
2078 case Primitive::kPrimInt:
2079 case Primitive::kPrimLong:
2080 __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
2081 break;
2082
2083 case Primitive::kPrimFloat:
2084 case Primitive::kPrimDouble:
Alexandre Rames67555f72014-11-18 10:55:16 +00002085 __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002086 break;
2087
2088 default:
2089 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2090 }
2091}
2092
2093void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) {
2094 LocationSummary* locations =
2095 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2096 InvokeRuntimeCallingConvention calling_convention;
2097 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002098 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(2)));
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002099 locations->SetOut(LocationFrom(x0));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002100 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(1)));
2101 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
2102 void*, uint32_t, int32_t, mirror::ArtMethod*>();
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002103}
2104
2105void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
2106 LocationSummary* locations = instruction->GetLocations();
2107 InvokeRuntimeCallingConvention calling_convention;
2108 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
2109 DCHECK(type_index.Is(w0));
2110 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002111 DCHECK(current_method.Is(w2));
Alexandre Rames67555f72014-11-18 10:55:16 +00002112 codegen_->LoadCurrentMethod(current_method);
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002113 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +00002114 codegen_->InvokeRuntime(
2115 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002116 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
2117 void*, uint32_t, int32_t, mirror::ArtMethod*>();
Alexandre Ramesfc19de82014-11-07 17:13:31 +00002118}
2119
Alexandre Rames5319def2014-10-23 10:03:10 +01002120void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
2121 LocationSummary* locations =
2122 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2123 InvokeRuntimeCallingConvention calling_convention;
2124 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
2125 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
2126 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002127 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, mirror::ArtMethod*>();
Alexandre Rames5319def2014-10-23 10:03:10 +01002128}
2129
2130void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) {
2131 LocationSummary* locations = instruction->GetLocations();
2132 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
2133 DCHECK(type_index.Is(w0));
2134 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
2135 DCHECK(current_method.Is(w1));
Alexandre Rames67555f72014-11-18 10:55:16 +00002136 codegen_->LoadCurrentMethod(current_method);
Alexandre Rames5319def2014-10-23 10:03:10 +01002137 __ Mov(type_index, instruction->GetTypeIndex());
Alexandre Rames67555f72014-11-18 10:55:16 +00002138 codegen_->InvokeRuntime(
2139 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002140 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, mirror::ArtMethod*>();
Alexandre Rames5319def2014-10-23 10:03:10 +01002141}
2142
2143void LocationsBuilderARM64::VisitNot(HNot* instruction) {
2144 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Alexandre Rames4e596512014-11-07 15:56:50 +00002145 locations->SetInAt(0, Location::RequiresRegister());
Alexandre Ramesfb4e5fa2014-11-06 12:41:16 +00002146 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Alexandre Rames5319def2014-10-23 10:03:10 +01002147}
2148
2149void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
2150 switch (instruction->InputAt(0)->GetType()) {
Alexandre Rames5319def2014-10-23 10:03:10 +01002151 case Primitive::kPrimInt:
Alexandre Rames5319def2014-10-23 10:03:10 +01002152 case Primitive::kPrimLong:
Roland Levillain55dcfb52014-10-24 18:09:09 +01002153 __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
Alexandre Rames5319def2014-10-23 10:03:10 +01002154 break;
2155
2156 default:
2157 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
2158 }
2159}
2160
2161void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
2162 LocationSummary* locations =
2163 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2164 locations->SetInAt(0, Location::RequiresRegister());
2165 if (instruction->HasUses()) {
2166 locations->SetOut(Location::SameAsFirstInput());
2167 }
2168}
2169
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002170void InstructionCodeGeneratorARM64::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002171 if (codegen_->CanMoveNullCheckToUser(instruction)) {
2172 return;
2173 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002174 Location obj = instruction->GetLocations()->InAt(0);
2175
2176 __ Ldr(wzr, HeapOperandFrom(obj, Offset(0)));
2177 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2178}
2179
2180void InstructionCodeGeneratorARM64::GenerateExplicitNullCheck(HNullCheck* instruction) {
Alexandre Rames5319def2014-10-23 10:03:10 +01002181 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction);
2182 codegen_->AddSlowPath(slow_path);
2183
2184 LocationSummary* locations = instruction->GetLocations();
2185 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00002186
2187 __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel());
Alexandre Rames5319def2014-10-23 10:03:10 +01002188}
2189
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002190void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
2191 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
2192 GenerateImplicitNullCheck(instruction);
2193 } else {
2194 GenerateExplicitNullCheck(instruction);
2195 }
2196}
2197
Alexandre Rames67555f72014-11-18 10:55:16 +00002198void LocationsBuilderARM64::VisitOr(HOr* instruction) {
2199 HandleBinaryOp(instruction);
2200}
2201
2202void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) {
2203 HandleBinaryOp(instruction);
2204}
2205
Alexandre Rames3e69f162014-12-10 10:36:50 +00002206void LocationsBuilderARM64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
2207 LOG(FATAL) << "Unreachable";
2208}
2209
2210void InstructionCodeGeneratorARM64::VisitParallelMove(HParallelMove* instruction) {
2211 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
2212}
2213
Alexandre Rames5319def2014-10-23 10:03:10 +01002214void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
2215 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2216 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2217 if (location.IsStackSlot()) {
2218 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2219 } else if (location.IsDoubleStackSlot()) {
2220 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2221 }
2222 locations->SetOut(location);
2223}
2224
2225void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) {
2226 // Nothing to do, the parameter is already at its location.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002227 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002228}
2229
2230void LocationsBuilderARM64::VisitPhi(HPhi* instruction) {
2231 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2232 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2233 locations->SetInAt(i, Location::Any());
2234 }
2235 locations->SetOut(Location::Any());
2236}
2237
2238void InstructionCodeGeneratorARM64::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002239 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002240 LOG(FATAL) << "Unreachable";
2241}
2242
Serban Constantinescu02164b32014-11-13 14:05:07 +00002243void LocationsBuilderARM64::VisitRem(HRem* rem) {
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002244 Primitive::Type type = rem->GetResultType();
Alexandre Rames542361f2015-01-29 16:57:31 +00002245 LocationSummary::CallKind call_kind =
2246 Primitive::IsFloatingPointType(type) ? LocationSummary::kCall : LocationSummary::kNoCall;
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002247 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2248
2249 switch (type) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002250 case Primitive::kPrimInt:
2251 case Primitive::kPrimLong:
2252 locations->SetInAt(0, Location::RequiresRegister());
2253 locations->SetInAt(1, Location::RequiresRegister());
2254 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2255 break;
2256
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002257 case Primitive::kPrimFloat:
2258 case Primitive::kPrimDouble: {
2259 InvokeRuntimeCallingConvention calling_convention;
2260 locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
2261 locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1)));
2262 locations->SetOut(calling_convention.GetReturnLocation(type));
2263
2264 break;
2265 }
2266
Serban Constantinescu02164b32014-11-13 14:05:07 +00002267 default:
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002268 LOG(FATAL) << "Unexpected rem type " << type;
Serban Constantinescu02164b32014-11-13 14:05:07 +00002269 }
2270}
2271
2272void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) {
2273 Primitive::Type type = rem->GetResultType();
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002274
Serban Constantinescu02164b32014-11-13 14:05:07 +00002275 switch (type) {
2276 case Primitive::kPrimInt:
2277 case Primitive::kPrimLong: {
2278 UseScratchRegisterScope temps(GetVIXLAssembler());
2279 Register dividend = InputRegisterAt(rem, 0);
2280 Register divisor = InputRegisterAt(rem, 1);
2281 Register output = OutputRegister(rem);
2282 Register temp = temps.AcquireSameSizeAs(output);
2283
2284 __ Sdiv(temp, dividend, divisor);
2285 __ Msub(output, temp, divisor, dividend);
2286 break;
2287 }
2288
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002289 case Primitive::kPrimFloat:
2290 case Primitive::kPrimDouble: {
2291 int32_t entry_offset = (type == Primitive::kPrimFloat) ? QUICK_ENTRY_POINT(pFmodf)
2292 : QUICK_ENTRY_POINT(pFmod);
2293 codegen_->InvokeRuntime(entry_offset, rem, rem->GetDexPc());
2294 break;
2295 }
2296
Serban Constantinescu02164b32014-11-13 14:05:07 +00002297 default:
2298 LOG(FATAL) << "Unexpected rem type " << type;
2299 }
2300}
2301
Alexandre Rames5319def2014-10-23 10:03:10 +01002302void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
2303 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2304 Primitive::Type return_type = instruction->InputAt(0)->GetType();
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002305 locations->SetInAt(0, ARM64ReturnLocation(return_type));
Alexandre Rames5319def2014-10-23 10:03:10 +01002306}
2307
2308void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002309 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002310 codegen_->GenerateFrameExit();
Alexandre Rames3e69f162014-12-10 10:36:50 +00002311 __ Ret();
Alexandre Rames5319def2014-10-23 10:03:10 +01002312}
2313
2314void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) {
2315 instruction->SetLocations(nullptr);
2316}
2317
2318void InstructionCodeGeneratorARM64::VisitReturnVoid(HReturnVoid* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002319 UNUSED(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002320 codegen_->GenerateFrameExit();
Alexandre Rames3e69f162014-12-10 10:36:50 +00002321 __ Ret();
Alexandre Rames5319def2014-10-23 10:03:10 +01002322}
2323
Serban Constantinescu02164b32014-11-13 14:05:07 +00002324void LocationsBuilderARM64::VisitShl(HShl* shl) {
2325 HandleShift(shl);
2326}
2327
2328void InstructionCodeGeneratorARM64::VisitShl(HShl* shl) {
2329 HandleShift(shl);
2330}
2331
2332void LocationsBuilderARM64::VisitShr(HShr* shr) {
2333 HandleShift(shr);
2334}
2335
2336void InstructionCodeGeneratorARM64::VisitShr(HShr* shr) {
2337 HandleShift(shr);
2338}
2339
Alexandre Rames5319def2014-10-23 10:03:10 +01002340void LocationsBuilderARM64::VisitStoreLocal(HStoreLocal* store) {
2341 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
2342 Primitive::Type field_type = store->InputAt(1)->GetType();
2343 switch (field_type) {
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002344 case Primitive::kPrimNot:
Alexandre Rames5319def2014-10-23 10:03:10 +01002345 case Primitive::kPrimBoolean:
2346 case Primitive::kPrimByte:
2347 case Primitive::kPrimChar:
2348 case Primitive::kPrimShort:
2349 case Primitive::kPrimInt:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002350 case Primitive::kPrimFloat:
Alexandre Rames5319def2014-10-23 10:03:10 +01002351 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
2352 break;
2353
2354 case Primitive::kPrimLong:
Alexandre Ramesa89086e2014-11-07 17:13:25 +00002355 case Primitive::kPrimDouble:
Alexandre Rames5319def2014-10-23 10:03:10 +01002356 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
2357 break;
2358
2359 default:
2360 LOG(FATAL) << "Unimplemented local type " << field_type;
2361 }
2362}
2363
2364void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002365 UNUSED(store);
Alexandre Rames5319def2014-10-23 10:03:10 +01002366}
2367
2368void LocationsBuilderARM64::VisitSub(HSub* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002369 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002370}
2371
2372void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002373 HandleBinaryOp(instruction);
Alexandre Rames5319def2014-10-23 10:03:10 +01002374}
2375
Alexandre Rames67555f72014-11-18 10:55:16 +00002376void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2377 LocationSummary* locations =
2378 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2379 locations->SetInAt(0, Location::RequiresRegister());
2380 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2381}
2382
2383void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002384 MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), instruction->GetFieldOffset());
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002385
2386 if (instruction->IsVolatile()) {
2387 if (kUseAcquireRelease) {
Calin Juravle77520bc2015-01-12 18:45:46 +00002388 // NB: LoadAcquire will record the pc info if needed.
2389 codegen_->LoadAcquire(instruction, OutputCPURegister(instruction), field);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002390 } else {
2391 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
2392 // For IRIW sequential consistency kLoadAny is not sufficient.
2393 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2394 }
2395 } else {
2396 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field);
2397 }
Alexandre Rames67555f72014-11-18 10:55:16 +00002398}
2399
2400void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Alexandre Rames5319def2014-10-23 10:03:10 +01002401 LocationSummary* locations =
2402 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2403 locations->SetInAt(0, Location::RequiresRegister());
2404 locations->SetInAt(1, Location::RequiresRegister());
Alexandre Rames5319def2014-10-23 10:03:10 +01002405}
2406
Alexandre Rames67555f72014-11-18 10:55:16 +00002407void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002408 Register cls = InputRegisterAt(instruction, 0);
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002409 CPURegister value = InputCPURegisterAt(instruction, 1);
Serban Constantinescu02164b32014-11-13 14:05:07 +00002410 Offset offset = instruction->GetFieldOffset();
Alexandre Rames67555f72014-11-18 10:55:16 +00002411 Primitive::Type field_type = instruction->GetFieldType();
Alexandre Rames5319def2014-10-23 10:03:10 +01002412
Serban Constantinescu02d81cc2015-01-05 16:08:49 +00002413 if (instruction->IsVolatile()) {
2414 if (kUseAcquireRelease) {
2415 codegen_->StoreRelease(field_type, value, HeapOperand(cls, offset));
2416 } else {
2417 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2418 codegen_->Store(field_type, value, HeapOperand(cls, offset));
2419 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2420 }
2421 } else {
2422 codegen_->Store(field_type, value, HeapOperand(cls, offset));
2423 }
2424
2425 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002426 codegen_->MarkGCCard(cls, Register(value));
2427 }
Alexandre Rames5319def2014-10-23 10:03:10 +01002428}
2429
2430void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
2431 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
2432}
2433
2434void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002435 HBasicBlock* block = instruction->GetBlock();
2436 if (block->GetLoopInformation() != nullptr) {
2437 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
2438 // The back edge will generate the suspend check.
2439 return;
2440 }
2441 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
2442 // The goto will generate the suspend check.
2443 return;
2444 }
2445 GenerateSuspendCheck(instruction, nullptr);
Alexandre Rames5319def2014-10-23 10:03:10 +01002446}
2447
2448void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
2449 temp->SetLocations(nullptr);
2450}
2451
2452void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) {
2453 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002454 UNUSED(temp);
Alexandre Rames5319def2014-10-23 10:03:10 +01002455}
2456
Alexandre Rames67555f72014-11-18 10:55:16 +00002457void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
2458 LocationSummary* locations =
2459 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2460 InvokeRuntimeCallingConvention calling_convention;
2461 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2462}
2463
2464void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
2465 codegen_->InvokeRuntime(
2466 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002467 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Alexandre Rames67555f72014-11-18 10:55:16 +00002468}
2469
2470void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
2471 LocationSummary* locations =
2472 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
2473 Primitive::Type input_type = conversion->GetInputType();
2474 Primitive::Type result_type = conversion->GetResultType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002475 DCHECK_NE(input_type, result_type);
Alexandre Rames67555f72014-11-18 10:55:16 +00002476 if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
2477 (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
2478 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
2479 }
2480
Alexandre Rames542361f2015-01-29 16:57:31 +00002481 if (Primitive::IsFloatingPointType(input_type)) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002482 locations->SetInAt(0, Location::RequiresFpuRegister());
2483 } else {
2484 locations->SetInAt(0, Location::RequiresRegister());
2485 }
2486
Alexandre Rames542361f2015-01-29 16:57:31 +00002487 if (Primitive::IsFloatingPointType(result_type)) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002488 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2489 } else {
2490 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2491 }
2492}
2493
2494void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
2495 Primitive::Type result_type = conversion->GetResultType();
2496 Primitive::Type input_type = conversion->GetInputType();
2497
2498 DCHECK_NE(input_type, result_type);
2499
Alexandre Rames542361f2015-01-29 16:57:31 +00002500 if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
Alexandre Rames67555f72014-11-18 10:55:16 +00002501 int result_size = Primitive::ComponentSize(result_type);
2502 int input_size = Primitive::ComponentSize(input_type);
Alexandre Rames3e69f162014-12-10 10:36:50 +00002503 int min_size = std::min(result_size, input_size);
Serban Constantinescu02164b32014-11-13 14:05:07 +00002504 Register output = OutputRegister(conversion);
2505 Register source = InputRegisterAt(conversion, 0);
Alexandre Rames3e69f162014-12-10 10:36:50 +00002506 if ((result_type == Primitive::kPrimChar) && (input_size < result_size)) {
2507 __ Ubfx(output, source, 0, result_size * kBitsPerByte);
2508 } else if ((result_type == Primitive::kPrimChar) ||
2509 ((input_type == Primitive::kPrimChar) && (result_size > input_size))) {
2510 __ Ubfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
Alexandre Rames67555f72014-11-18 10:55:16 +00002511 } else {
Alexandre Rames3e69f162014-12-10 10:36:50 +00002512 __ Sbfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
Alexandre Rames67555f72014-11-18 10:55:16 +00002513 }
Alexandre Rames542361f2015-01-29 16:57:31 +00002514 } else if (Primitive::IsFloatingPointType(result_type) && Primitive::IsIntegralType(input_type)) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002515 __ Scvtf(OutputFPRegister(conversion), InputRegisterAt(conversion, 0));
Alexandre Rames542361f2015-01-29 16:57:31 +00002516 } else if (Primitive::IsIntegralType(result_type) && Primitive::IsFloatingPointType(input_type)) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002517 CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
2518 __ Fcvtzs(OutputRegister(conversion), InputFPRegisterAt(conversion, 0));
Alexandre Rames542361f2015-01-29 16:57:31 +00002519 } else if (Primitive::IsFloatingPointType(result_type) &&
2520 Primitive::IsFloatingPointType(input_type)) {
Serban Constantinescu02164b32014-11-13 14:05:07 +00002521 __ Fcvt(OutputFPRegister(conversion), InputFPRegisterAt(conversion, 0));
2522 } else {
2523 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
2524 << " to " << result_type;
Alexandre Rames67555f72014-11-18 10:55:16 +00002525 }
Serban Constantinescu02164b32014-11-13 14:05:07 +00002526}
Alexandre Rames67555f72014-11-18 10:55:16 +00002527
Serban Constantinescu02164b32014-11-13 14:05:07 +00002528void LocationsBuilderARM64::VisitUShr(HUShr* ushr) {
2529 HandleShift(ushr);
2530}
2531
2532void InstructionCodeGeneratorARM64::VisitUShr(HUShr* ushr) {
2533 HandleShift(ushr);
Alexandre Rames67555f72014-11-18 10:55:16 +00002534}
2535
2536void LocationsBuilderARM64::VisitXor(HXor* instruction) {
2537 HandleBinaryOp(instruction);
2538}
2539
2540void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) {
2541 HandleBinaryOp(instruction);
2542}
2543
2544#undef __
2545#undef QUICK_ENTRY_POINT
2546
Alexandre Rames5319def2014-10-23 10:03:10 +01002547} // namespace arm64
2548} // namespace art