1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "code_generator_arm64.h"
18 
19 #include "arch/arm64/instruction_set_features_arm64.h"
20 #include "art_method.h"
21 #include "common_arm64.h"
22 #include "entrypoints/quick/quick_entrypoints.h"
23 #include "entrypoints/quick/quick_entrypoints_enum.h"
24 #include "gc/accounting/card_table.h"
25 #include "intrinsics.h"
26 #include "intrinsics_arm64.h"
27 #include "mirror/array-inl.h"
28 #include "mirror/class-inl.h"
29 #include "offsets.h"
30 #include "thread.h"
31 #include "utils/arm64/assembler_arm64.h"
32 #include "utils/assembler.h"
33 #include "utils/stack_checks.h"
34 
35 
36 using namespace vixl;   // NOLINT(build/namespaces)
37 
38 #ifdef __
39 #error "ARM64 Codegen VIXL macro-assembler macro already defined."
40 #endif
41 
42 namespace art {
43 
44 namespace arm64 {
45 
46 using helpers::CPURegisterFrom;
47 using helpers::DRegisterFrom;
48 using helpers::FPRegisterFrom;
49 using helpers::HeapOperand;
50 using helpers::HeapOperandFrom;
51 using helpers::InputCPURegisterAt;
52 using helpers::InputFPRegisterAt;
53 using helpers::InputRegisterAt;
54 using helpers::InputOperandAt;
55 using helpers::Int64ConstantFrom;
56 using helpers::LocationFrom;
57 using helpers::OperandFromMemOperand;
58 using helpers::OutputCPURegister;
59 using helpers::OutputFPRegister;
60 using helpers::OutputRegister;
61 using helpers::RegisterFrom;
62 using helpers::StackOperandFrom;
63 using helpers::VIXLRegCodeFromART;
64 using helpers::WRegisterFrom;
65 using helpers::XRegisterFrom;
66 using helpers::ARM64EncodableConstantOrRegister;
67 
68 static constexpr int kCurrentMethodStackOffset = 0;
69 
ARM64Condition(IfCondition cond)70 inline Condition ARM64Condition(IfCondition cond) {
71   switch (cond) {
72     case kCondEQ: return eq;
73     case kCondNE: return ne;
74     case kCondLT: return lt;
75     case kCondLE: return le;
76     case kCondGT: return gt;
77     case kCondGE: return ge;
78     default:
79       LOG(FATAL) << "Unknown if condition";
80   }
81   return nv;  // Unreachable.
82 }
83 
ARM64ReturnLocation(Primitive::Type return_type)84 Location ARM64ReturnLocation(Primitive::Type return_type) {
85   DCHECK_NE(return_type, Primitive::kPrimVoid);
86   // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the
87   // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`,
88   // but we use the exact registers for clarity.
89   if (return_type == Primitive::kPrimFloat) {
90     return LocationFrom(s0);
91   } else if (return_type == Primitive::kPrimDouble) {
92     return LocationFrom(d0);
93   } else if (return_type == Primitive::kPrimLong) {
94     return LocationFrom(x0);
95   } else {
96     return LocationFrom(w0);
97   }
98 }
99 
GetReturnLocation(Primitive::Type return_type)100 Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type return_type) {
101   return ARM64ReturnLocation(return_type);
102 }
103 
104 #define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
105 #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
106 
107 class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
108  public:
BoundsCheckSlowPathARM64(HBoundsCheck * instruction,Location index_location,Location length_location)109   BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
110                            Location index_location,
111                            Location length_location)
112       : instruction_(instruction),
113         index_location_(index_location),
114         length_location_(length_location) {}
115 
116 
EmitNativeCode(CodeGenerator * codegen)117   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
118     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
119     __ Bind(GetEntryLabel());
120     // We're moving two locations to locations that could overlap, so we need a parallel
121     // move resolver.
122     InvokeRuntimeCallingConvention calling_convention;
123     codegen->EmitParallelMoves(
124         index_location_, LocationFrom(calling_convention.GetRegisterAt(0)), Primitive::kPrimInt,
125         length_location_, LocationFrom(calling_convention.GetRegisterAt(1)), Primitive::kPrimInt);
126     arm64_codegen->InvokeRuntime(
127         QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
128     CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
129   }
130 
131  private:
132   HBoundsCheck* const instruction_;
133   const Location index_location_;
134   const Location length_location_;
135 
136   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
137 };
138 
139 class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 {
140  public:
DivZeroCheckSlowPathARM64(HDivZeroCheck * instruction)141   explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : instruction_(instruction) {}
142 
EmitNativeCode(CodeGenerator * codegen)143   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
144     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
145     __ Bind(GetEntryLabel());
146     arm64_codegen->InvokeRuntime(
147         QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
148     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
149   }
150 
151  private:
152   HDivZeroCheck* const instruction_;
153   DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64);
154 };
155 
156 class LoadClassSlowPathARM64 : public SlowPathCodeARM64 {
157  public:
LoadClassSlowPathARM64(HLoadClass * cls,HInstruction * at,uint32_t dex_pc,bool do_clinit)158   LoadClassSlowPathARM64(HLoadClass* cls,
159                          HInstruction* at,
160                          uint32_t dex_pc,
161                          bool do_clinit)
162       : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
163     DCHECK(at->IsLoadClass() || at->IsClinitCheck());
164   }
165 
EmitNativeCode(CodeGenerator * codegen)166   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
167     LocationSummary* locations = at_->GetLocations();
168     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
169 
170     __ Bind(GetEntryLabel());
171     SaveLiveRegisters(codegen, locations);
172 
173     InvokeRuntimeCallingConvention calling_convention;
174     __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
175     int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
176                                             : QUICK_ENTRY_POINT(pInitializeType);
177     arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
178     if (do_clinit_) {
179       CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
180     } else {
181       CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
182     }
183 
184     // Move the class to the desired location.
185     Location out = locations->Out();
186     if (out.IsValid()) {
187       DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
188       Primitive::Type type = at_->GetType();
189       arm64_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
190     }
191 
192     RestoreLiveRegisters(codegen, locations);
193     __ B(GetExitLabel());
194   }
195 
196  private:
197   // The class this slow path will load.
198   HLoadClass* const cls_;
199 
200   // The instruction where this slow path is happening.
201   // (Might be the load class or an initialization check).
202   HInstruction* const at_;
203 
204   // The dex PC of `at_`.
205   const uint32_t dex_pc_;
206 
207   // Whether to initialize the class.
208   const bool do_clinit_;
209 
210   DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
211 };
212 
213 class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
214  public:
LoadStringSlowPathARM64(HLoadString * instruction)215   explicit LoadStringSlowPathARM64(HLoadString* instruction) : instruction_(instruction) {}
216 
EmitNativeCode(CodeGenerator * codegen)217   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
218     LocationSummary* locations = instruction_->GetLocations();
219     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
220     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
221 
222     __ Bind(GetEntryLabel());
223     SaveLiveRegisters(codegen, locations);
224 
225     InvokeRuntimeCallingConvention calling_convention;
226     __ Mov(calling_convention.GetRegisterAt(0).W(), instruction_->GetStringIndex());
227     arm64_codegen->InvokeRuntime(
228         QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
229     CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
230     Primitive::Type type = instruction_->GetType();
231     arm64_codegen->MoveLocation(locations->Out(), calling_convention.GetReturnLocation(type), type);
232 
233     RestoreLiveRegisters(codegen, locations);
234     __ B(GetExitLabel());
235   }
236 
237  private:
238   HLoadString* const instruction_;
239 
240   DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
241 };
242 
243 class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
244  public:
NullCheckSlowPathARM64(HNullCheck * instr)245   explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {}
246 
EmitNativeCode(CodeGenerator * codegen)247   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
248     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
249     __ Bind(GetEntryLabel());
250     arm64_codegen->InvokeRuntime(
251         QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
252     CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
253   }
254 
255  private:
256   HNullCheck* const instruction_;
257 
258   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM64);
259 };
260 
261 class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 {
262  public:
SuspendCheckSlowPathARM64(HSuspendCheck * instruction,HBasicBlock * successor)263   explicit SuspendCheckSlowPathARM64(HSuspendCheck* instruction,
264                                      HBasicBlock* successor)
265       : instruction_(instruction), successor_(successor) {}
266 
EmitNativeCode(CodeGenerator * codegen)267   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
268     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
269     __ Bind(GetEntryLabel());
270     SaveLiveRegisters(codegen, instruction_->GetLocations());
271     arm64_codegen->InvokeRuntime(
272         QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
273     CheckEntrypointTypes<kQuickTestSuspend, void, void>();
274     RestoreLiveRegisters(codegen, instruction_->GetLocations());
275     if (successor_ == nullptr) {
276       __ B(GetReturnLabel());
277     } else {
278       __ B(arm64_codegen->GetLabelOf(successor_));
279     }
280   }
281 
GetReturnLabel()282   vixl::Label* GetReturnLabel() {
283     DCHECK(successor_ == nullptr);
284     return &return_label_;
285   }
286 
GetSuccessor() const287   HBasicBlock* GetSuccessor() const {
288     return successor_;
289   }
290 
291  private:
292   HSuspendCheck* const instruction_;
293   // If not null, the block to branch to after the suspend check.
294   HBasicBlock* const successor_;
295 
296   // If `successor_` is null, the label to branch to after the suspend check.
297   vixl::Label return_label_;
298 
299   DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
300 };
301 
302 class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
303  public:
TypeCheckSlowPathARM64(HInstruction * instruction,Location class_to_check,Location object_class,uint32_t dex_pc)304   TypeCheckSlowPathARM64(HInstruction* instruction,
305                          Location class_to_check,
306                          Location object_class,
307                          uint32_t dex_pc)
308       : instruction_(instruction),
309         class_to_check_(class_to_check),
310         object_class_(object_class),
311         dex_pc_(dex_pc) {}
312 
EmitNativeCode(CodeGenerator * codegen)313   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
314     LocationSummary* locations = instruction_->GetLocations();
315     DCHECK(instruction_->IsCheckCast()
316            || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
317     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
318 
319     __ Bind(GetEntryLabel());
320     SaveLiveRegisters(codegen, locations);
321 
322     // We're moving two locations to locations that could overlap, so we need a parallel
323     // move resolver.
324     InvokeRuntimeCallingConvention calling_convention;
325     codegen->EmitParallelMoves(
326         class_to_check_, LocationFrom(calling_convention.GetRegisterAt(0)), Primitive::kPrimNot,
327         object_class_, LocationFrom(calling_convention.GetRegisterAt(1)), Primitive::kPrimNot);
328 
329     if (instruction_->IsInstanceOf()) {
330       arm64_codegen->InvokeRuntime(
331           QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_, this);
332       Primitive::Type ret_type = instruction_->GetType();
333       Location ret_loc = calling_convention.GetReturnLocation(ret_type);
334       arm64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
335       CheckEntrypointTypes<kQuickInstanceofNonTrivial, uint32_t,
336                            const mirror::Class*, const mirror::Class*>();
337     } else {
338       DCHECK(instruction_->IsCheckCast());
339       arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_, this);
340       CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
341     }
342 
343     RestoreLiveRegisters(codegen, locations);
344     __ B(GetExitLabel());
345   }
346 
347  private:
348   HInstruction* const instruction_;
349   const Location class_to_check_;
350   const Location object_class_;
351   uint32_t dex_pc_;
352 
353   DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64);
354 };
355 
356 class DeoptimizationSlowPathARM64 : public SlowPathCodeARM64 {
357  public:
DeoptimizationSlowPathARM64(HInstruction * instruction)358   explicit DeoptimizationSlowPathARM64(HInstruction* instruction)
359     : instruction_(instruction) {}
360 
EmitNativeCode(CodeGenerator * codegen)361   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
362     __ Bind(GetEntryLabel());
363     SaveLiveRegisters(codegen, instruction_->GetLocations());
364     DCHECK(instruction_->IsDeoptimize());
365     HDeoptimize* deoptimize = instruction_->AsDeoptimize();
366     uint32_t dex_pc = deoptimize->GetDexPc();
367     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
368     arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
369   }
370 
371  private:
372   HInstruction* const instruction_;
373   DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM64);
374 };
375 
376 #undef __
377 
GetNextLocation(Primitive::Type type)378 Location InvokeDexCallingConventionVisitorARM64::GetNextLocation(Primitive::Type type) {
379   Location next_location;
380   if (type == Primitive::kPrimVoid) {
381     LOG(FATAL) << "Unreachable type " << type;
382   }
383 
384   if (Primitive::IsFloatingPointType(type) &&
385       (float_index_ < calling_convention.GetNumberOfFpuRegisters())) {
386     next_location = LocationFrom(calling_convention.GetFpuRegisterAt(float_index_++));
387   } else if (!Primitive::IsFloatingPointType(type) &&
388              (gp_index_ < calling_convention.GetNumberOfRegisters())) {
389     next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++));
390   } else {
391     size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
392     next_location = Primitive::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
393                                                  : Location::StackSlot(stack_offset);
394   }
395 
396   // Space on the stack is reserved for all arguments.
397   stack_index_ += Primitive::Is64BitType(type) ? 2 : 1;
398   return next_location;
399 }
400 
CodeGeneratorARM64(HGraph * graph,const Arm64InstructionSetFeatures & isa_features,const CompilerOptions & compiler_options)401 CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph,
402                                        const Arm64InstructionSetFeatures& isa_features,
403                                        const CompilerOptions& compiler_options)
404     : CodeGenerator(graph,
405                     kNumberOfAllocatableRegisters,
406                     kNumberOfAllocatableFPRegisters,
407                     kNumberOfAllocatableRegisterPairs,
408                     callee_saved_core_registers.list(),
409                     callee_saved_fp_registers.list(),
410                     compiler_options),
411       block_labels_(nullptr),
412       location_builder_(graph, this),
413       instruction_visitor_(graph, this),
414       move_resolver_(graph->GetArena(), this),
415       isa_features_(isa_features) {
416   // Save the link register (containing the return address) to mimic Quick.
417   AddAllocatedRegister(LocationFrom(lr));
418 }
419 
420 #undef __
421 #define __ GetVIXLAssembler()->
422 
Finalize(CodeAllocator * allocator)423 void CodeGeneratorARM64::Finalize(CodeAllocator* allocator) {
424   // Ensure we emit the literal pool.
425   __ FinalizeCode();
426   CodeGenerator::Finalize(allocator);
427 }
428 
PrepareForEmitNativeCode()429 void ParallelMoveResolverARM64::PrepareForEmitNativeCode() {
430   // Note: There are 6 kinds of moves:
431   // 1. constant -> GPR/FPR (non-cycle)
432   // 2. constant -> stack (non-cycle)
433   // 3. GPR/FPR -> GPR/FPR
434   // 4. GPR/FPR -> stack
435   // 5. stack -> GPR/FPR
436   // 6. stack -> stack (non-cycle)
437   // Case 1, 2 and 6 should never be included in a dependency cycle on ARM64. For case 3, 4, and 5
438   // VIXL uses at most 1 GPR. VIXL has 2 GPR and 1 FPR temps, and there should be no intersecting
439   // cycles on ARM64, so we always have 1 GPR and 1 FPR available VIXL temps to resolve the
440   // dependency.
441   vixl_temps_.Open(GetVIXLAssembler());
442 }
443 
FinishEmitNativeCode()444 void ParallelMoveResolverARM64::FinishEmitNativeCode() {
445   vixl_temps_.Close();
446 }
447 
AllocateScratchLocationFor(Location::Kind kind)448 Location ParallelMoveResolverARM64::AllocateScratchLocationFor(Location::Kind kind) {
449   DCHECK(kind == Location::kRegister || kind == Location::kFpuRegister ||
450          kind == Location::kStackSlot || kind == Location::kDoubleStackSlot);
451   kind = (kind == Location::kFpuRegister) ? Location::kFpuRegister : Location::kRegister;
452   Location scratch = GetScratchLocation(kind);
453   if (!scratch.Equals(Location::NoLocation())) {
454     return scratch;
455   }
456   // Allocate from VIXL temp registers.
457   if (kind == Location::kRegister) {
458     scratch = LocationFrom(vixl_temps_.AcquireX());
459   } else {
460     DCHECK(kind == Location::kFpuRegister);
461     scratch = LocationFrom(vixl_temps_.AcquireD());
462   }
463   AddScratchLocation(scratch);
464   return scratch;
465 }
466 
FreeScratchLocation(Location loc)467 void ParallelMoveResolverARM64::FreeScratchLocation(Location loc) {
468   if (loc.IsRegister()) {
469     vixl_temps_.Release(XRegisterFrom(loc));
470   } else {
471     DCHECK(loc.IsFpuRegister());
472     vixl_temps_.Release(DRegisterFrom(loc));
473   }
474   RemoveScratchLocation(loc);
475 }
476 
EmitMove(size_t index)477 void ParallelMoveResolverARM64::EmitMove(size_t index) {
478   MoveOperands* move = moves_.Get(index);
479   codegen_->MoveLocation(move->GetDestination(), move->GetSource());
480 }
481 
GenerateFrameEntry()482 void CodeGeneratorARM64::GenerateFrameEntry() {
483   MacroAssembler* masm = GetVIXLAssembler();
484   BlockPoolsScope block_pools(masm);
485   __ Bind(&frame_entry_label_);
486 
487   bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kArm64) || !IsLeafMethod();
488   if (do_overflow_check) {
489     UseScratchRegisterScope temps(masm);
490     Register temp = temps.AcquireX();
491     DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
492     __ Sub(temp, sp, static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
493     __ Ldr(wzr, MemOperand(temp, 0));
494     RecordPcInfo(nullptr, 0);
495   }
496 
497   if (!HasEmptyFrame()) {
498     int frame_size = GetFrameSize();
499     // Stack layout:
500     //      sp[frame_size - 8]        : lr.
501     //      ...                       : other preserved core registers.
502     //      ...                       : other preserved fp registers.
503     //      ...                       : reserved frame space.
504     //      sp[0]                     : current method.
505     __ Str(kArtMethodRegister, MemOperand(sp, -frame_size, PreIndex));
506     GetAssembler()->cfi().AdjustCFAOffset(frame_size);
507     GetAssembler()->SpillRegisters(GetFramePreservedCoreRegisters(),
508         frame_size - GetCoreSpillSize());
509     GetAssembler()->SpillRegisters(GetFramePreservedFPRegisters(),
510         frame_size - FrameEntrySpillSize());
511   }
512 }
513 
GenerateFrameExit()514 void CodeGeneratorARM64::GenerateFrameExit() {
515   BlockPoolsScope block_pools(GetVIXLAssembler());
516   GetAssembler()->cfi().RememberState();
517   if (!HasEmptyFrame()) {
518     int frame_size = GetFrameSize();
519     GetAssembler()->UnspillRegisters(GetFramePreservedFPRegisters(),
520         frame_size - FrameEntrySpillSize());
521     GetAssembler()->UnspillRegisters(GetFramePreservedCoreRegisters(),
522         frame_size - GetCoreSpillSize());
523     __ Drop(frame_size);
524     GetAssembler()->cfi().AdjustCFAOffset(-frame_size);
525   }
526   __ Ret();
527   GetAssembler()->cfi().RestoreState();
528   GetAssembler()->cfi().DefCFAOffset(GetFrameSize());
529 }
530 
Bind(HBasicBlock * block)531 void CodeGeneratorARM64::Bind(HBasicBlock* block) {
532   __ Bind(GetLabelOf(block));
533 }
534 
Move(HInstruction * instruction,Location location,HInstruction * move_for)535 void CodeGeneratorARM64::Move(HInstruction* instruction,
536                               Location location,
537                               HInstruction* move_for) {
538   LocationSummary* locations = instruction->GetLocations();
539   if (locations != nullptr && locations->Out().Equals(location)) {
540     return;
541   }
542 
543   Primitive::Type type = instruction->GetType();
544   DCHECK_NE(type, Primitive::kPrimVoid);
545 
546   if (instruction->IsIntConstant()
547       || instruction->IsLongConstant()
548       || instruction->IsNullConstant()) {
549     int64_t value = GetInt64ValueOf(instruction->AsConstant());
550     if (location.IsRegister()) {
551       Register dst = RegisterFrom(location, type);
552       DCHECK(((instruction->IsIntConstant() || instruction->IsNullConstant()) && dst.Is32Bits()) ||
553              (instruction->IsLongConstant() && dst.Is64Bits()));
554       __ Mov(dst, value);
555     } else {
556       DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
557       UseScratchRegisterScope temps(GetVIXLAssembler());
558       Register temp = (instruction->IsIntConstant() || instruction->IsNullConstant())
559           ? temps.AcquireW()
560           : temps.AcquireX();
561       __ Mov(temp, value);
562       __ Str(temp, StackOperandFrom(location));
563     }
564   } else if (instruction->IsTemporary()) {
565     Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
566     MoveLocation(location, temp_location, type);
567   } else if (instruction->IsLoadLocal()) {
568     uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
569     if (Primitive::Is64BitType(type)) {
570       MoveLocation(location, Location::DoubleStackSlot(stack_slot), type);
571     } else {
572       MoveLocation(location, Location::StackSlot(stack_slot), type);
573     }
574 
575   } else {
576     DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
577     MoveLocation(location, locations->Out(), type);
578   }
579 }
580 
GetStackLocation(HLoadLocal * load) const581 Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const {
582   Primitive::Type type = load->GetType();
583 
584   switch (type) {
585     case Primitive::kPrimNot:
586     case Primitive::kPrimInt:
587     case Primitive::kPrimFloat:
588       return Location::StackSlot(GetStackSlot(load->GetLocal()));
589 
590     case Primitive::kPrimLong:
591     case Primitive::kPrimDouble:
592       return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
593 
594     case Primitive::kPrimBoolean:
595     case Primitive::kPrimByte:
596     case Primitive::kPrimChar:
597     case Primitive::kPrimShort:
598     case Primitive::kPrimVoid:
599       LOG(FATAL) << "Unexpected type " << type;
600   }
601 
602   LOG(FATAL) << "Unreachable";
603   return Location::NoLocation();
604 }
605 
MarkGCCard(Register object,Register value)606 void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
607   UseScratchRegisterScope temps(GetVIXLAssembler());
608   Register card = temps.AcquireX();
609   Register temp = temps.AcquireW();   // Index within the CardTable - 32bit.
610   vixl::Label done;
611   __ Cbz(value, &done);
612   __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
613   __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
614   __ Strb(card, MemOperand(card, temp.X()));
615   __ Bind(&done);
616 }
617 
SetupBlockedRegisters(bool is_baseline) const618 void CodeGeneratorARM64::SetupBlockedRegisters(bool is_baseline) const {
619   // Blocked core registers:
620   //      lr        : Runtime reserved.
621   //      tr        : Runtime reserved.
622   //      xSuspend  : Runtime reserved. TODO: Unblock this when the runtime stops using it.
623   //      ip1       : VIXL core temp.
624   //      ip0       : VIXL core temp.
625   //
626   // Blocked fp registers:
627   //      d31       : VIXL fp temp.
628   CPURegList reserved_core_registers = vixl_reserved_core_registers;
629   reserved_core_registers.Combine(runtime_reserved_core_registers);
630   while (!reserved_core_registers.IsEmpty()) {
631     blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true;
632   }
633 
634   CPURegList reserved_fp_registers = vixl_reserved_fp_registers;
635   while (!reserved_fp_registers.IsEmpty()) {
636     blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().code()] = true;
637   }
638 
639   if (is_baseline) {
640     CPURegList reserved_core_baseline_registers = callee_saved_core_registers;
641     while (!reserved_core_baseline_registers.IsEmpty()) {
642       blocked_core_registers_[reserved_core_baseline_registers.PopLowestIndex().code()] = true;
643     }
644 
645     CPURegList reserved_fp_baseline_registers = callee_saved_fp_registers;
646     while (!reserved_fp_baseline_registers.IsEmpty()) {
647       blocked_fpu_registers_[reserved_fp_baseline_registers.PopLowestIndex().code()] = true;
648     }
649   }
650 }
651 
AllocateFreeRegister(Primitive::Type type) const652 Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const {
653   if (type == Primitive::kPrimVoid) {
654     LOG(FATAL) << "Unreachable type " << type;
655   }
656 
657   if (Primitive::IsFloatingPointType(type)) {
658     ssize_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfAllocatableFPRegisters);
659     DCHECK_NE(reg, -1);
660     return Location::FpuRegisterLocation(reg);
661   } else {
662     ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfAllocatableRegisters);
663     DCHECK_NE(reg, -1);
664     return Location::RegisterLocation(reg);
665   }
666 }
667 
SaveCoreRegister(size_t stack_index,uint32_t reg_id)668 size_t CodeGeneratorARM64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
669   Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
670   __ Str(reg, MemOperand(sp, stack_index));
671   return kArm64WordSize;
672 }
673 
RestoreCoreRegister(size_t stack_index,uint32_t reg_id)674 size_t CodeGeneratorARM64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
675   Register reg = Register(VIXLRegCodeFromART(reg_id), kXRegSize);
676   __ Ldr(reg, MemOperand(sp, stack_index));
677   return kArm64WordSize;
678 }
679 
SaveFloatingPointRegister(size_t stack_index,uint32_t reg_id)680 size_t CodeGeneratorARM64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
681   FPRegister reg = FPRegister(reg_id, kDRegSize);
682   __ Str(reg, MemOperand(sp, stack_index));
683   return kArm64WordSize;
684 }
685 
RestoreFloatingPointRegister(size_t stack_index,uint32_t reg_id)686 size_t CodeGeneratorARM64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
687   FPRegister reg = FPRegister(reg_id, kDRegSize);
688   __ Ldr(reg, MemOperand(sp, stack_index));
689   return kArm64WordSize;
690 }
691 
DumpCoreRegister(std::ostream & stream,int reg) const692 void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
693   stream << Arm64ManagedRegister::FromXRegister(XRegister(reg));
694 }
695 
DumpFloatingPointRegister(std::ostream & stream,int reg) const696 void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
697   stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
698 }
699 
MoveConstant(CPURegister destination,HConstant * constant)700 void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
701   if (constant->IsIntConstant()) {
702     __ Mov(Register(destination), constant->AsIntConstant()->GetValue());
703   } else if (constant->IsLongConstant()) {
704     __ Mov(Register(destination), constant->AsLongConstant()->GetValue());
705   } else if (constant->IsNullConstant()) {
706     __ Mov(Register(destination), 0);
707   } else if (constant->IsFloatConstant()) {
708     __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
709   } else {
710     DCHECK(constant->IsDoubleConstant());
711     __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue());
712   }
713 }
714 
715 
CoherentConstantAndType(Location constant,Primitive::Type type)716 static bool CoherentConstantAndType(Location constant, Primitive::Type type) {
717   DCHECK(constant.IsConstant());
718   HConstant* cst = constant.GetConstant();
719   return (cst->IsIntConstant() && type == Primitive::kPrimInt) ||
720          // Null is mapped to a core W register, which we associate with kPrimInt.
721          (cst->IsNullConstant() && type == Primitive::kPrimInt) ||
722          (cst->IsLongConstant() && type == Primitive::kPrimLong) ||
723          (cst->IsFloatConstant() && type == Primitive::kPrimFloat) ||
724          (cst->IsDoubleConstant() && type == Primitive::kPrimDouble);
725 }
726 
MoveLocation(Location destination,Location source,Primitive::Type type)727 void CodeGeneratorARM64::MoveLocation(Location destination, Location source, Primitive::Type type) {
728   if (source.Equals(destination)) {
729     return;
730   }
731 
732   // A valid move can always be inferred from the destination and source
733   // locations. When moving from and to a register, the argument type can be
734   // used to generate 32bit instead of 64bit moves. In debug mode we also
735   // checks the coherency of the locations and the type.
736   bool unspecified_type = (type == Primitive::kPrimVoid);
737 
738   if (destination.IsRegister() || destination.IsFpuRegister()) {
739     if (unspecified_type) {
740       HConstant* src_cst = source.IsConstant() ? source.GetConstant() : nullptr;
741       if (source.IsStackSlot() ||
742           (src_cst != nullptr && (src_cst->IsIntConstant()
743                                   || src_cst->IsFloatConstant()
744                                   || src_cst->IsNullConstant()))) {
745         // For stack slots and 32bit constants, a 64bit type is appropriate.
746         type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
747       } else {
748         // If the source is a double stack slot or a 64bit constant, a 64bit
749         // type is appropriate. Else the source is a register, and since the
750         // type has not been specified, we chose a 64bit type to force a 64bit
751         // move.
752         type = destination.IsRegister() ? Primitive::kPrimLong : Primitive::kPrimDouble;
753       }
754     }
755     DCHECK((destination.IsFpuRegister() && Primitive::IsFloatingPointType(type)) ||
756            (destination.IsRegister() && !Primitive::IsFloatingPointType(type)));
757     CPURegister dst = CPURegisterFrom(destination, type);
758     if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
759       DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot());
760       __ Ldr(dst, StackOperandFrom(source));
761     } else if (source.IsConstant()) {
762       DCHECK(CoherentConstantAndType(source, type));
763       MoveConstant(dst, source.GetConstant());
764     } else {
765       if (destination.IsRegister()) {
766         __ Mov(Register(dst), RegisterFrom(source, type));
767       } else {
768         DCHECK(destination.IsFpuRegister());
769         __ Fmov(FPRegister(dst), FPRegisterFrom(source, type));
770       }
771     }
772   } else {  // The destination is not a register. It must be a stack slot.
773     DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
774     if (source.IsRegister() || source.IsFpuRegister()) {
775       if (unspecified_type) {
776         if (source.IsRegister()) {
777           type = destination.IsStackSlot() ? Primitive::kPrimInt : Primitive::kPrimLong;
778         } else {
779           type = destination.IsStackSlot() ? Primitive::kPrimFloat : Primitive::kPrimDouble;
780         }
781       }
782       DCHECK((destination.IsDoubleStackSlot() == Primitive::Is64BitType(type)) &&
783              (source.IsFpuRegister() == Primitive::IsFloatingPointType(type)));
784       __ Str(CPURegisterFrom(source, type), StackOperandFrom(destination));
785     } else if (source.IsConstant()) {
786       DCHECK(unspecified_type || CoherentConstantAndType(source, type));
787       UseScratchRegisterScope temps(GetVIXLAssembler());
788       HConstant* src_cst = source.GetConstant();
789       CPURegister temp;
790       if (src_cst->IsIntConstant() || src_cst->IsNullConstant()) {
791         temp = temps.AcquireW();
792       } else if (src_cst->IsLongConstant()) {
793         temp = temps.AcquireX();
794       } else if (src_cst->IsFloatConstant()) {
795         temp = temps.AcquireS();
796       } else {
797         DCHECK(src_cst->IsDoubleConstant());
798         temp = temps.AcquireD();
799       }
800       MoveConstant(temp, src_cst);
801       __ Str(temp, StackOperandFrom(destination));
802     } else {
803       DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
804       DCHECK(source.IsDoubleStackSlot() == destination.IsDoubleStackSlot());
805       UseScratchRegisterScope temps(GetVIXLAssembler());
806       // There is generally less pressure on FP registers.
807       FPRegister temp = destination.IsDoubleStackSlot() ? temps.AcquireD() : temps.AcquireS();
808       __ Ldr(temp, StackOperandFrom(source));
809       __ Str(temp, StackOperandFrom(destination));
810     }
811   }
812 }
813 
Load(Primitive::Type type,CPURegister dst,const MemOperand & src)814 void CodeGeneratorARM64::Load(Primitive::Type type,
815                               CPURegister dst,
816                               const MemOperand& src) {
817   switch (type) {
818     case Primitive::kPrimBoolean:
819       __ Ldrb(Register(dst), src);
820       break;
821     case Primitive::kPrimByte:
822       __ Ldrsb(Register(dst), src);
823       break;
824     case Primitive::kPrimShort:
825       __ Ldrsh(Register(dst), src);
826       break;
827     case Primitive::kPrimChar:
828       __ Ldrh(Register(dst), src);
829       break;
830     case Primitive::kPrimInt:
831     case Primitive::kPrimNot:
832     case Primitive::kPrimLong:
833     case Primitive::kPrimFloat:
834     case Primitive::kPrimDouble:
835       DCHECK_EQ(dst.Is64Bits(), Primitive::Is64BitType(type));
836       __ Ldr(dst, src);
837       break;
838     case Primitive::kPrimVoid:
839       LOG(FATAL) << "Unreachable type " << type;
840   }
841 }
842 
LoadAcquire(HInstruction * instruction,CPURegister dst,const MemOperand & src)843 void CodeGeneratorARM64::LoadAcquire(HInstruction* instruction,
844                                      CPURegister dst,
845                                      const MemOperand& src) {
846   MacroAssembler* masm = GetVIXLAssembler();
847   BlockPoolsScope block_pools(masm);
848   UseScratchRegisterScope temps(masm);
849   Register temp_base = temps.AcquireX();
850   Primitive::Type type = instruction->GetType();
851 
852   DCHECK(!src.IsPreIndex());
853   DCHECK(!src.IsPostIndex());
854 
855   // TODO(vixl): Let the MacroAssembler handle MemOperand.
856   __ Add(temp_base, src.base(), OperandFromMemOperand(src));
857   MemOperand base = MemOperand(temp_base);
858   switch (type) {
859     case Primitive::kPrimBoolean:
860       __ Ldarb(Register(dst), base);
861       MaybeRecordImplicitNullCheck(instruction);
862       break;
863     case Primitive::kPrimByte:
864       __ Ldarb(Register(dst), base);
865       MaybeRecordImplicitNullCheck(instruction);
866       __ Sbfx(Register(dst), Register(dst), 0, Primitive::ComponentSize(type) * kBitsPerByte);
867       break;
868     case Primitive::kPrimChar:
869       __ Ldarh(Register(dst), base);
870       MaybeRecordImplicitNullCheck(instruction);
871       break;
872     case Primitive::kPrimShort:
873       __ Ldarh(Register(dst), base);
874       MaybeRecordImplicitNullCheck(instruction);
875       __ Sbfx(Register(dst), Register(dst), 0, Primitive::ComponentSize(type) * kBitsPerByte);
876       break;
877     case Primitive::kPrimInt:
878     case Primitive::kPrimNot:
879     case Primitive::kPrimLong:
880       DCHECK_EQ(dst.Is64Bits(), Primitive::Is64BitType(type));
881       __ Ldar(Register(dst), base);
882       MaybeRecordImplicitNullCheck(instruction);
883       break;
884     case Primitive::kPrimFloat:
885     case Primitive::kPrimDouble: {
886       DCHECK(dst.IsFPRegister());
887       DCHECK_EQ(dst.Is64Bits(), Primitive::Is64BitType(type));
888 
889       Register temp = dst.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
890       __ Ldar(temp, base);
891       MaybeRecordImplicitNullCheck(instruction);
892       __ Fmov(FPRegister(dst), temp);
893       break;
894     }
895     case Primitive::kPrimVoid:
896       LOG(FATAL) << "Unreachable type " << type;
897   }
898 }
899 
Store(Primitive::Type type,CPURegister src,const MemOperand & dst)900 void CodeGeneratorARM64::Store(Primitive::Type type,
901                                CPURegister src,
902                                const MemOperand& dst) {
903   switch (type) {
904     case Primitive::kPrimBoolean:
905     case Primitive::kPrimByte:
906       __ Strb(Register(src), dst);
907       break;
908     case Primitive::kPrimChar:
909     case Primitive::kPrimShort:
910       __ Strh(Register(src), dst);
911       break;
912     case Primitive::kPrimInt:
913     case Primitive::kPrimNot:
914     case Primitive::kPrimLong:
915     case Primitive::kPrimFloat:
916     case Primitive::kPrimDouble:
917       DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
918       __ Str(src, dst);
919       break;
920     case Primitive::kPrimVoid:
921       LOG(FATAL) << "Unreachable type " << type;
922   }
923 }
924 
StoreRelease(Primitive::Type type,CPURegister src,const MemOperand & dst)925 void CodeGeneratorARM64::StoreRelease(Primitive::Type type,
926                                       CPURegister src,
927                                       const MemOperand& dst) {
928   UseScratchRegisterScope temps(GetVIXLAssembler());
929   Register temp_base = temps.AcquireX();
930 
931   DCHECK(!dst.IsPreIndex());
932   DCHECK(!dst.IsPostIndex());
933 
934   // TODO(vixl): Let the MacroAssembler handle this.
935   Operand op = OperandFromMemOperand(dst);
936   __ Add(temp_base, dst.base(), op);
937   MemOperand base = MemOperand(temp_base);
938   switch (type) {
939     case Primitive::kPrimBoolean:
940     case Primitive::kPrimByte:
941       __ Stlrb(Register(src), base);
942       break;
943     case Primitive::kPrimChar:
944     case Primitive::kPrimShort:
945       __ Stlrh(Register(src), base);
946       break;
947     case Primitive::kPrimInt:
948     case Primitive::kPrimNot:
949     case Primitive::kPrimLong:
950       DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
951       __ Stlr(Register(src), base);
952       break;
953     case Primitive::kPrimFloat:
954     case Primitive::kPrimDouble: {
955       DCHECK(src.IsFPRegister());
956       DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
957 
958       Register temp = src.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
959       __ Fmov(temp, FPRegister(src));
960       __ Stlr(temp, base);
961       break;
962     }
963     case Primitive::kPrimVoid:
964       LOG(FATAL) << "Unreachable type " << type;
965   }
966 }
967 
LoadCurrentMethod(vixl::Register current_method)968 void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) {
969   DCHECK(RequiresCurrentMethod());
970   CHECK(current_method.IsX());
971   __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
972 }
973 
InvokeRuntime(int32_t entry_point_offset,HInstruction * instruction,uint32_t dex_pc,SlowPathCode * slow_path)974 void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
975                                        HInstruction* instruction,
976                                        uint32_t dex_pc,
977                                        SlowPathCode* slow_path) {
978   BlockPoolsScope block_pools(GetVIXLAssembler());
979   __ Ldr(lr, MemOperand(tr, entry_point_offset));
980   __ Blr(lr);
981   if (instruction != nullptr) {
982     RecordPcInfo(instruction, dex_pc, slow_path);
983     DCHECK(instruction->IsSuspendCheck()
984         || instruction->IsBoundsCheck()
985         || instruction->IsNullCheck()
986         || instruction->IsDivZeroCheck()
987         || !IsLeafMethod());
988     }
989 }
990 
GenerateClassInitializationCheck(SlowPathCodeARM64 * slow_path,vixl::Register class_reg)991 void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
992                                                                      vixl::Register class_reg) {
993   UseScratchRegisterScope temps(GetVIXLAssembler());
994   Register temp = temps.AcquireW();
995   size_t status_offset = mirror::Class::StatusOffset().SizeValue();
996   bool use_acquire_release = codegen_->GetInstructionSetFeatures().PreferAcquireRelease();
997 
998   // Even if the initialized flag is set, we need to ensure consistent memory ordering.
999   if (use_acquire_release) {
1000     // TODO(vixl): Let the MacroAssembler handle MemOperand.
1001     __ Add(temp, class_reg, status_offset);
1002     __ Ldar(temp, HeapOperand(temp));
1003     __ Cmp(temp, mirror::Class::kStatusInitialized);
1004     __ B(lt, slow_path->GetEntryLabel());
1005   } else {
1006     __ Ldr(temp, HeapOperand(class_reg, status_offset));
1007     __ Cmp(temp, mirror::Class::kStatusInitialized);
1008     __ B(lt, slow_path->GetEntryLabel());
1009     __ Dmb(InnerShareable, BarrierReads);
1010   }
1011   __ Bind(slow_path->GetExitLabel());
1012 }
1013 
GenerateMemoryBarrier(MemBarrierKind kind)1014 void InstructionCodeGeneratorARM64::GenerateMemoryBarrier(MemBarrierKind kind) {
1015   BarrierType type = BarrierAll;
1016 
1017   switch (kind) {
1018     case MemBarrierKind::kAnyAny:
1019     case MemBarrierKind::kAnyStore: {
1020       type = BarrierAll;
1021       break;
1022     }
1023     case MemBarrierKind::kLoadAny: {
1024       type = BarrierReads;
1025       break;
1026     }
1027     case MemBarrierKind::kStoreStore: {
1028       type = BarrierWrites;
1029       break;
1030     }
1031     default:
1032       LOG(FATAL) << "Unexpected memory barrier " << kind;
1033   }
1034   __ Dmb(InnerShareable, type);
1035 }
1036 
GenerateSuspendCheck(HSuspendCheck * instruction,HBasicBlock * successor)1037 void InstructionCodeGeneratorARM64::GenerateSuspendCheck(HSuspendCheck* instruction,
1038                                                          HBasicBlock* successor) {
1039   SuspendCheckSlowPathARM64* slow_path =
1040       down_cast<SuspendCheckSlowPathARM64*>(instruction->GetSlowPath());
1041   if (slow_path == nullptr) {
1042     slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM64(instruction, successor);
1043     instruction->SetSlowPath(slow_path);
1044     codegen_->AddSlowPath(slow_path);
1045     if (successor != nullptr) {
1046       DCHECK(successor->IsLoopHeader());
1047       codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
1048     }
1049   } else {
1050     DCHECK_EQ(slow_path->GetSuccessor(), successor);
1051   }
1052 
1053   UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
1054   Register temp = temps.AcquireW();
1055 
1056   __ Ldrh(temp, MemOperand(tr, Thread::ThreadFlagsOffset<kArm64WordSize>().SizeValue()));
1057   if (successor == nullptr) {
1058     __ Cbnz(temp, slow_path->GetEntryLabel());
1059     __ Bind(slow_path->GetReturnLabel());
1060   } else {
1061     __ Cbz(temp, codegen_->GetLabelOf(successor));
1062     __ B(slow_path->GetEntryLabel());
1063     // slow_path will return to GetLabelOf(successor).
1064   }
1065 }
1066 
InstructionCodeGeneratorARM64(HGraph * graph,CodeGeneratorARM64 * codegen)1067 InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
1068                                                              CodeGeneratorARM64* codegen)
1069       : HGraphVisitor(graph),
1070         assembler_(codegen->GetAssembler()),
1071         codegen_(codegen) {}
1072 
1073 #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M)              \
1074   /* No unimplemented IR. */
1075 
1076 #define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
1077 
1078 enum UnimplementedInstructionBreakCode {
1079   // Using a base helps identify when we hit such breakpoints.
1080   UnimplementedInstructionBreakCodeBaseCode = 0x900,
1081 #define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name),
1082   FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION)
1083 #undef ENUM_UNIMPLEMENTED_INSTRUCTION
1084 };
1085 
1086 #define DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS(name)                               \
1087   void InstructionCodeGeneratorARM64::Visit##name(H##name* instr) {                   \
1088     UNUSED(instr);                                                                    \
1089     __ Brk(UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name));                               \
1090   }                                                                                   \
1091   void LocationsBuilderARM64::Visit##name(H##name* instr) {                           \
1092     LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); \
1093     locations->SetOut(Location::Any());                                               \
1094   }
FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS)1095   FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS)
1096 #undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS
1097 
1098 #undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE
1099 #undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION
1100 
1101 void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) {
1102   DCHECK_EQ(instr->InputCount(), 2U);
1103   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1104   Primitive::Type type = instr->GetResultType();
1105   switch (type) {
1106     case Primitive::kPrimInt:
1107     case Primitive::kPrimLong:
1108       locations->SetInAt(0, Location::RequiresRegister());
1109       locations->SetInAt(1, ARM64EncodableConstantOrRegister(instr->InputAt(1), instr));
1110       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1111       break;
1112 
1113     case Primitive::kPrimFloat:
1114     case Primitive::kPrimDouble:
1115       locations->SetInAt(0, Location::RequiresFpuRegister());
1116       locations->SetInAt(1, Location::RequiresFpuRegister());
1117       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1118       break;
1119 
1120     default:
1121       LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type;
1122   }
1123 }
1124 
HandleFieldGet(HInstruction * instruction)1125 void LocationsBuilderARM64::HandleFieldGet(HInstruction* instruction) {
1126   LocationSummary* locations =
1127       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1128   locations->SetInAt(0, Location::RequiresRegister());
1129   if (Primitive::IsFloatingPointType(instruction->GetType())) {
1130     locations->SetOut(Location::RequiresFpuRegister());
1131   } else {
1132     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1133   }
1134 }
1135 
HandleFieldGet(HInstruction * instruction,const FieldInfo & field_info)1136 void InstructionCodeGeneratorARM64::HandleFieldGet(HInstruction* instruction,
1137                                                    const FieldInfo& field_info) {
1138   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
1139   BlockPoolsScope block_pools(GetVIXLAssembler());
1140 
1141   MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), field_info.GetFieldOffset());
1142   bool use_acquire_release = codegen_->GetInstructionSetFeatures().PreferAcquireRelease();
1143 
1144   if (field_info.IsVolatile()) {
1145     if (use_acquire_release) {
1146       // NB: LoadAcquire will record the pc info if needed.
1147       codegen_->LoadAcquire(instruction, OutputCPURegister(instruction), field);
1148     } else {
1149       codegen_->Load(field_info.GetFieldType(), OutputCPURegister(instruction), field);
1150       codegen_->MaybeRecordImplicitNullCheck(instruction);
1151       // For IRIW sequential consistency kLoadAny is not sufficient.
1152       GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
1153     }
1154   } else {
1155     codegen_->Load(field_info.GetFieldType(), OutputCPURegister(instruction), field);
1156     codegen_->MaybeRecordImplicitNullCheck(instruction);
1157   }
1158 }
1159 
HandleFieldSet(HInstruction * instruction)1160 void LocationsBuilderARM64::HandleFieldSet(HInstruction* instruction) {
1161   LocationSummary* locations =
1162       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1163   locations->SetInAt(0, Location::RequiresRegister());
1164   if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
1165     locations->SetInAt(1, Location::RequiresFpuRegister());
1166   } else {
1167     locations->SetInAt(1, Location::RequiresRegister());
1168   }
1169 }
1170 
HandleFieldSet(HInstruction * instruction,const FieldInfo & field_info)1171 void InstructionCodeGeneratorARM64::HandleFieldSet(HInstruction* instruction,
1172                                                    const FieldInfo& field_info) {
1173   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
1174   BlockPoolsScope block_pools(GetVIXLAssembler());
1175 
1176   Register obj = InputRegisterAt(instruction, 0);
1177   CPURegister value = InputCPURegisterAt(instruction, 1);
1178   Offset offset = field_info.GetFieldOffset();
1179   Primitive::Type field_type = field_info.GetFieldType();
1180   bool use_acquire_release = codegen_->GetInstructionSetFeatures().PreferAcquireRelease();
1181 
1182   if (field_info.IsVolatile()) {
1183     if (use_acquire_release) {
1184       codegen_->StoreRelease(field_type, value, HeapOperand(obj, offset));
1185       codegen_->MaybeRecordImplicitNullCheck(instruction);
1186     } else {
1187       GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
1188       codegen_->Store(field_type, value, HeapOperand(obj, offset));
1189       codegen_->MaybeRecordImplicitNullCheck(instruction);
1190       GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
1191     }
1192   } else {
1193     codegen_->Store(field_type, value, HeapOperand(obj, offset));
1194     codegen_->MaybeRecordImplicitNullCheck(instruction);
1195   }
1196 
1197   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
1198     codegen_->MarkGCCard(obj, Register(value));
1199   }
1200 }
1201 
HandleBinaryOp(HBinaryOperation * instr)1202 void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) {
1203   Primitive::Type type = instr->GetType();
1204 
1205   switch (type) {
1206     case Primitive::kPrimInt:
1207     case Primitive::kPrimLong: {
1208       Register dst = OutputRegister(instr);
1209       Register lhs = InputRegisterAt(instr, 0);
1210       Operand rhs = InputOperandAt(instr, 1);
1211       if (instr->IsAdd()) {
1212         __ Add(dst, lhs, rhs);
1213       } else if (instr->IsAnd()) {
1214         __ And(dst, lhs, rhs);
1215       } else if (instr->IsOr()) {
1216         __ Orr(dst, lhs, rhs);
1217       } else if (instr->IsSub()) {
1218         __ Sub(dst, lhs, rhs);
1219       } else {
1220         DCHECK(instr->IsXor());
1221         __ Eor(dst, lhs, rhs);
1222       }
1223       break;
1224     }
1225     case Primitive::kPrimFloat:
1226     case Primitive::kPrimDouble: {
1227       FPRegister dst = OutputFPRegister(instr);
1228       FPRegister lhs = InputFPRegisterAt(instr, 0);
1229       FPRegister rhs = InputFPRegisterAt(instr, 1);
1230       if (instr->IsAdd()) {
1231         __ Fadd(dst, lhs, rhs);
1232       } else if (instr->IsSub()) {
1233         __ Fsub(dst, lhs, rhs);
1234       } else {
1235         LOG(FATAL) << "Unexpected floating-point binary operation";
1236       }
1237       break;
1238     }
1239     default:
1240       LOG(FATAL) << "Unexpected binary operation type " << type;
1241   }
1242 }
1243 
HandleShift(HBinaryOperation * instr)1244 void LocationsBuilderARM64::HandleShift(HBinaryOperation* instr) {
1245   DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
1246 
1247   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1248   Primitive::Type type = instr->GetResultType();
1249   switch (type) {
1250     case Primitive::kPrimInt:
1251     case Primitive::kPrimLong: {
1252       locations->SetInAt(0, Location::RequiresRegister());
1253       locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1254       locations->SetOut(Location::RequiresRegister());
1255       break;
1256     }
1257     default:
1258       LOG(FATAL) << "Unexpected shift type " << type;
1259   }
1260 }
1261 
HandleShift(HBinaryOperation * instr)1262 void InstructionCodeGeneratorARM64::HandleShift(HBinaryOperation* instr) {
1263   DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr());
1264 
1265   Primitive::Type type = instr->GetType();
1266   switch (type) {
1267     case Primitive::kPrimInt:
1268     case Primitive::kPrimLong: {
1269       Register dst = OutputRegister(instr);
1270       Register lhs = InputRegisterAt(instr, 0);
1271       Operand rhs = InputOperandAt(instr, 1);
1272       if (rhs.IsImmediate()) {
1273         uint32_t shift_value = (type == Primitive::kPrimInt)
1274           ? static_cast<uint32_t>(rhs.immediate() & kMaxIntShiftValue)
1275           : static_cast<uint32_t>(rhs.immediate() & kMaxLongShiftValue);
1276         if (instr->IsShl()) {
1277           __ Lsl(dst, lhs, shift_value);
1278         } else if (instr->IsShr()) {
1279           __ Asr(dst, lhs, shift_value);
1280         } else {
1281           __ Lsr(dst, lhs, shift_value);
1282         }
1283       } else {
1284         Register rhs_reg = dst.IsX() ? rhs.reg().X() : rhs.reg().W();
1285 
1286         if (instr->IsShl()) {
1287           __ Lsl(dst, lhs, rhs_reg);
1288         } else if (instr->IsShr()) {
1289           __ Asr(dst, lhs, rhs_reg);
1290         } else {
1291           __ Lsr(dst, lhs, rhs_reg);
1292         }
1293       }
1294       break;
1295     }
1296     default:
1297       LOG(FATAL) << "Unexpected shift operation type " << type;
1298   }
1299 }
1300 
VisitAdd(HAdd * instruction)1301 void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
1302   HandleBinaryOp(instruction);
1303 }
1304 
VisitAdd(HAdd * instruction)1305 void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
1306   HandleBinaryOp(instruction);
1307 }
1308 
VisitAnd(HAnd * instruction)1309 void LocationsBuilderARM64::VisitAnd(HAnd* instruction) {
1310   HandleBinaryOp(instruction);
1311 }
1312 
VisitAnd(HAnd * instruction)1313 void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) {
1314   HandleBinaryOp(instruction);
1315 }
1316 
VisitArrayGet(HArrayGet * instruction)1317 void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
1318   LocationSummary* locations =
1319       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1320   locations->SetInAt(0, Location::RequiresRegister());
1321   locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1322   if (Primitive::IsFloatingPointType(instruction->GetType())) {
1323     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1324   } else {
1325     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1326   }
1327 }
1328 
VisitArrayGet(HArrayGet * instruction)1329 void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
1330   LocationSummary* locations = instruction->GetLocations();
1331   Primitive::Type type = instruction->GetType();
1332   Register obj = InputRegisterAt(instruction, 0);
1333   Location index = locations->InAt(1);
1334   size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value();
1335   MemOperand source = HeapOperand(obj);
1336   MacroAssembler* masm = GetVIXLAssembler();
1337   UseScratchRegisterScope temps(masm);
1338   BlockPoolsScope block_pools(masm);
1339 
1340   if (index.IsConstant()) {
1341     offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
1342     source = HeapOperand(obj, offset);
1343   } else {
1344     Register temp = temps.AcquireSameSizeAs(obj);
1345     Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
1346     __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type)));
1347     source = HeapOperand(temp, offset);
1348   }
1349 
1350   codegen_->Load(type, OutputCPURegister(instruction), source);
1351   codegen_->MaybeRecordImplicitNullCheck(instruction);
1352 }
1353 
VisitArrayLength(HArrayLength * instruction)1354 void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
1355   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1356   locations->SetInAt(0, Location::RequiresRegister());
1357   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1358 }
1359 
VisitArrayLength(HArrayLength * instruction)1360 void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
1361   BlockPoolsScope block_pools(GetVIXLAssembler());
1362   __ Ldr(OutputRegister(instruction),
1363          HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset()));
1364   codegen_->MaybeRecordImplicitNullCheck(instruction);
1365 }
1366 
VisitArraySet(HArraySet * instruction)1367 void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
1368   if (instruction->NeedsTypeCheck()) {
1369     LocationSummary* locations =
1370         new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1371     InvokeRuntimeCallingConvention calling_convention;
1372     locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
1373     locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
1374     locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2)));
1375   } else {
1376     LocationSummary* locations =
1377         new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1378     locations->SetInAt(0, Location::RequiresRegister());
1379     locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1380     if (Primitive::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
1381       locations->SetInAt(2, Location::RequiresFpuRegister());
1382     } else {
1383       locations->SetInAt(2, Location::RequiresRegister());
1384     }
1385   }
1386 }
1387 
VisitArraySet(HArraySet * instruction)1388 void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
1389   Primitive::Type value_type = instruction->GetComponentType();
1390   LocationSummary* locations = instruction->GetLocations();
1391   bool needs_runtime_call = locations->WillCall();
1392 
1393   if (needs_runtime_call) {
1394     codegen_->InvokeRuntime(
1395         QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc(), nullptr);
1396     CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
1397   } else {
1398     Register obj = InputRegisterAt(instruction, 0);
1399     CPURegister value = InputCPURegisterAt(instruction, 2);
1400     Location index = locations->InAt(1);
1401     size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
1402     MemOperand destination = HeapOperand(obj);
1403     MacroAssembler* masm = GetVIXLAssembler();
1404     BlockPoolsScope block_pools(masm);
1405     {
1406       // We use a block to end the scratch scope before the write barrier, thus
1407       // freeing the temporary registers so they can be used in `MarkGCCard`.
1408       UseScratchRegisterScope temps(masm);
1409 
1410       if (index.IsConstant()) {
1411         offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
1412         destination = HeapOperand(obj, offset);
1413       } else {
1414         Register temp = temps.AcquireSameSizeAs(obj);
1415         Register index_reg = InputRegisterAt(instruction, 1);
1416         __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type)));
1417         destination = HeapOperand(temp, offset);
1418       }
1419 
1420       codegen_->Store(value_type, value, destination);
1421       codegen_->MaybeRecordImplicitNullCheck(instruction);
1422     }
1423     if (CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue())) {
1424       codegen_->MarkGCCard(obj, value.W());
1425     }
1426   }
1427 }
1428 
VisitBoundsCheck(HBoundsCheck * instruction)1429 void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1430   LocationSummary* locations =
1431       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1432   locations->SetInAt(0, Location::RequiresRegister());
1433   locations->SetInAt(1, ARM64EncodableConstantOrRegister(instruction->InputAt(1), instruction));
1434   if (instruction->HasUses()) {
1435     locations->SetOut(Location::SameAsFirstInput());
1436   }
1437 }
1438 
VisitBoundsCheck(HBoundsCheck * instruction)1439 void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
1440   LocationSummary* locations = instruction->GetLocations();
1441   BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(
1442       instruction, locations->InAt(0), locations->InAt(1));
1443   codegen_->AddSlowPath(slow_path);
1444 
1445   __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
1446   __ B(slow_path->GetEntryLabel(), hs);
1447 }
1448 
VisitCheckCast(HCheckCast * instruction)1449 void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
1450   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1451       instruction, LocationSummary::kCallOnSlowPath);
1452   locations->SetInAt(0, Location::RequiresRegister());
1453   locations->SetInAt(1, Location::RequiresRegister());
1454   locations->AddTemp(Location::RequiresRegister());
1455 }
1456 
VisitCheckCast(HCheckCast * instruction)1457 void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
1458   LocationSummary* locations = instruction->GetLocations();
1459   Register obj = InputRegisterAt(instruction, 0);;
1460   Register cls = InputRegisterAt(instruction, 1);;
1461   Register obj_cls = WRegisterFrom(instruction->GetLocations()->GetTemp(0));
1462 
1463   SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(
1464       instruction, locations->InAt(1), LocationFrom(obj_cls), instruction->GetDexPc());
1465   codegen_->AddSlowPath(slow_path);
1466 
1467   // Avoid null check if we know obj is not null.
1468   if (instruction->MustDoNullCheck()) {
1469     __ Cbz(obj, slow_path->GetExitLabel());
1470   }
1471   // Compare the class of `obj` with `cls`.
1472   __ Ldr(obj_cls, HeapOperand(obj, mirror::Object::ClassOffset()));
1473   __ Cmp(obj_cls, cls);
1474   __ B(ne, slow_path->GetEntryLabel());
1475   __ Bind(slow_path->GetExitLabel());
1476 }
1477 
VisitClinitCheck(HClinitCheck * check)1478 void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) {
1479   LocationSummary* locations =
1480       new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
1481   locations->SetInAt(0, Location::RequiresRegister());
1482   if (check->HasUses()) {
1483     locations->SetOut(Location::SameAsFirstInput());
1484   }
1485 }
1486 
VisitClinitCheck(HClinitCheck * check)1487 void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) {
1488   // We assume the class is not null.
1489   SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
1490       check->GetLoadClass(), check, check->GetDexPc(), true);
1491   codegen_->AddSlowPath(slow_path);
1492   GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
1493 }
1494 
VisitCompare(HCompare * compare)1495 void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
1496   LocationSummary* locations =
1497       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
1498   Primitive::Type in_type = compare->InputAt(0)->GetType();
1499   switch (in_type) {
1500     case Primitive::kPrimLong: {
1501       locations->SetInAt(0, Location::RequiresRegister());
1502       locations->SetInAt(1, ARM64EncodableConstantOrRegister(compare->InputAt(1), compare));
1503       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1504       break;
1505     }
1506     case Primitive::kPrimFloat:
1507     case Primitive::kPrimDouble: {
1508       locations->SetInAt(0, Location::RequiresFpuRegister());
1509       HInstruction* right = compare->InputAt(1);
1510       if ((right->IsFloatConstant() && (right->AsFloatConstant()->GetValue() == 0.0f)) ||
1511           (right->IsDoubleConstant() && (right->AsDoubleConstant()->GetValue() == 0.0))) {
1512         locations->SetInAt(1, Location::ConstantLocation(right->AsConstant()));
1513       } else {
1514         locations->SetInAt(1, Location::RequiresFpuRegister());
1515       }
1516       locations->SetOut(Location::RequiresRegister());
1517       break;
1518     }
1519     default:
1520       LOG(FATAL) << "Unexpected type for compare operation " << in_type;
1521   }
1522 }
1523 
VisitCompare(HCompare * compare)1524 void InstructionCodeGeneratorARM64::VisitCompare(HCompare* compare) {
1525   Primitive::Type in_type = compare->InputAt(0)->GetType();
1526 
1527   //  0 if: left == right
1528   //  1 if: left  > right
1529   // -1 if: left  < right
1530   switch (in_type) {
1531     case Primitive::kPrimLong: {
1532       Register result = OutputRegister(compare);
1533       Register left = InputRegisterAt(compare, 0);
1534       Operand right = InputOperandAt(compare, 1);
1535 
1536       __ Cmp(left, right);
1537       __ Cset(result, ne);
1538       __ Cneg(result, result, lt);
1539       break;
1540     }
1541     case Primitive::kPrimFloat:
1542     case Primitive::kPrimDouble: {
1543       Register result = OutputRegister(compare);
1544       FPRegister left = InputFPRegisterAt(compare, 0);
1545       if (compare->GetLocations()->InAt(1).IsConstant()) {
1546         if (kIsDebugBuild) {
1547           HInstruction* right = compare->GetLocations()->InAt(1).GetConstant();
1548           DCHECK((right->IsFloatConstant() && (right->AsFloatConstant()->GetValue() == 0.0f)) ||
1549                   (right->IsDoubleConstant() && (right->AsDoubleConstant()->GetValue() == 0.0)));
1550         }
1551         // 0.0 is the only immediate that can be encoded directly in a FCMP instruction.
1552         __ Fcmp(left, 0.0);
1553       } else {
1554         __ Fcmp(left, InputFPRegisterAt(compare, 1));
1555       }
1556       if (compare->IsGtBias()) {
1557         __ Cset(result, ne);
1558       } else {
1559         __ Csetm(result, ne);
1560       }
1561       __ Cneg(result, result, compare->IsGtBias() ? mi : gt);
1562       break;
1563     }
1564     default:
1565       LOG(FATAL) << "Unimplemented compare type " << in_type;
1566   }
1567 }
1568 
VisitCondition(HCondition * instruction)1569 void LocationsBuilderARM64::VisitCondition(HCondition* instruction) {
1570   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1571   locations->SetInAt(0, Location::RequiresRegister());
1572   locations->SetInAt(1, ARM64EncodableConstantOrRegister(instruction->InputAt(1), instruction));
1573   if (instruction->NeedsMaterialization()) {
1574     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1575   }
1576 }
1577 
VisitCondition(HCondition * instruction)1578 void InstructionCodeGeneratorARM64::VisitCondition(HCondition* instruction) {
1579   if (!instruction->NeedsMaterialization()) {
1580     return;
1581   }
1582 
1583   LocationSummary* locations = instruction->GetLocations();
1584   Register lhs = InputRegisterAt(instruction, 0);
1585   Operand rhs = InputOperandAt(instruction, 1);
1586   Register res = RegisterFrom(locations->Out(), instruction->GetType());
1587   Condition cond = ARM64Condition(instruction->GetCondition());
1588 
1589   __ Cmp(lhs, rhs);
1590   __ Cset(res, cond);
1591 }
1592 
1593 #define FOR_EACH_CONDITION_INSTRUCTION(M)                                                \
1594   M(Equal)                                                                               \
1595   M(NotEqual)                                                                            \
1596   M(LessThan)                                                                            \
1597   M(LessThanOrEqual)                                                                     \
1598   M(GreaterThan)                                                                         \
1599   M(GreaterThanOrEqual)
1600 #define DEFINE_CONDITION_VISITORS(Name)                                                  \
1601 void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }         \
1602 void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }
FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)1603 FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
1604 #undef DEFINE_CONDITION_VISITORS
1605 #undef FOR_EACH_CONDITION_INSTRUCTION
1606 
1607 void LocationsBuilderARM64::VisitDiv(HDiv* div) {
1608   LocationSummary* locations =
1609       new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
1610   switch (div->GetResultType()) {
1611     case Primitive::kPrimInt:
1612     case Primitive::kPrimLong:
1613       locations->SetInAt(0, Location::RequiresRegister());
1614       locations->SetInAt(1, Location::RequiresRegister());
1615       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1616       break;
1617 
1618     case Primitive::kPrimFloat:
1619     case Primitive::kPrimDouble:
1620       locations->SetInAt(0, Location::RequiresFpuRegister());
1621       locations->SetInAt(1, Location::RequiresFpuRegister());
1622       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1623       break;
1624 
1625     default:
1626       LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1627   }
1628 }
1629 
VisitDiv(HDiv * div)1630 void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) {
1631   Primitive::Type type = div->GetResultType();
1632   switch (type) {
1633     case Primitive::kPrimInt:
1634     case Primitive::kPrimLong:
1635       __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
1636       break;
1637 
1638     case Primitive::kPrimFloat:
1639     case Primitive::kPrimDouble:
1640       __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1));
1641       break;
1642 
1643     default:
1644       LOG(FATAL) << "Unexpected div type " << type;
1645   }
1646 }
1647 
VisitDivZeroCheck(HDivZeroCheck * instruction)1648 void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1649   LocationSummary* locations =
1650       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1651   locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
1652   if (instruction->HasUses()) {
1653     locations->SetOut(Location::SameAsFirstInput());
1654   }
1655 }
1656 
VisitDivZeroCheck(HDivZeroCheck * instruction)1657 void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
1658   SlowPathCodeARM64* slow_path =
1659       new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction);
1660   codegen_->AddSlowPath(slow_path);
1661   Location value = instruction->GetLocations()->InAt(0);
1662 
1663   Primitive::Type type = instruction->GetType();
1664 
1665   if ((type != Primitive::kPrimInt) && (type != Primitive::kPrimLong)) {
1666       LOG(FATAL) << "Unexpected type " << type << "for DivZeroCheck.";
1667     return;
1668   }
1669 
1670   if (value.IsConstant()) {
1671     int64_t divisor = Int64ConstantFrom(value);
1672     if (divisor == 0) {
1673       __ B(slow_path->GetEntryLabel());
1674     } else {
1675       // A division by a non-null constant is valid. We don't need to perform
1676       // any check, so simply fall through.
1677     }
1678   } else {
1679     __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
1680   }
1681 }
1682 
VisitDoubleConstant(HDoubleConstant * constant)1683 void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1684   LocationSummary* locations =
1685       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1686   locations->SetOut(Location::ConstantLocation(constant));
1687 }
1688 
VisitDoubleConstant(HDoubleConstant * constant)1689 void InstructionCodeGeneratorARM64::VisitDoubleConstant(HDoubleConstant* constant) {
1690   UNUSED(constant);
1691   // Will be generated at use site.
1692 }
1693 
VisitExit(HExit * exit)1694 void LocationsBuilderARM64::VisitExit(HExit* exit) {
1695   exit->SetLocations(nullptr);
1696 }
1697 
VisitExit(HExit * exit)1698 void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) {
1699   UNUSED(exit);
1700 }
1701 
VisitFloatConstant(HFloatConstant * constant)1702 void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) {
1703   LocationSummary* locations =
1704       new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1705   locations->SetOut(Location::ConstantLocation(constant));
1706 }
1707 
VisitFloatConstant(HFloatConstant * constant)1708 void InstructionCodeGeneratorARM64::VisitFloatConstant(HFloatConstant* constant) {
1709   UNUSED(constant);
1710   // Will be generated at use site.
1711 }
1712 
VisitGoto(HGoto * got)1713 void LocationsBuilderARM64::VisitGoto(HGoto* got) {
1714   got->SetLocations(nullptr);
1715 }
1716 
VisitGoto(HGoto * got)1717 void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
1718   HBasicBlock* successor = got->GetSuccessor();
1719   DCHECK(!successor->IsExitBlock());
1720   HBasicBlock* block = got->GetBlock();
1721   HInstruction* previous = got->GetPrevious();
1722   HLoopInformation* info = block->GetLoopInformation();
1723 
1724   if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
1725     codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
1726     GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1727     return;
1728   }
1729   if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1730     GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1731   }
1732   if (!codegen_->GoesToNextBlock(block, successor)) {
1733     __ B(codegen_->GetLabelOf(successor));
1734   }
1735 }
1736 
GenerateTestAndBranch(HInstruction * instruction,vixl::Label * true_target,vixl::Label * false_target,vixl::Label * always_true_target)1737 void InstructionCodeGeneratorARM64::GenerateTestAndBranch(HInstruction* instruction,
1738                                                           vixl::Label* true_target,
1739                                                           vixl::Label* false_target,
1740                                                           vixl::Label* always_true_target) {
1741   HInstruction* cond = instruction->InputAt(0);
1742   HCondition* condition = cond->AsCondition();
1743 
1744   if (cond->IsIntConstant()) {
1745     int32_t cond_value = cond->AsIntConstant()->GetValue();
1746     if (cond_value == 1) {
1747       if (always_true_target != nullptr) {
1748         __ B(always_true_target);
1749       }
1750       return;
1751     } else {
1752       DCHECK_EQ(cond_value, 0);
1753     }
1754   } else if (!cond->IsCondition() || condition->NeedsMaterialization()) {
1755     // The condition instruction has been materialized, compare the output to 0.
1756     Location cond_val = instruction->GetLocations()->InAt(0);
1757     DCHECK(cond_val.IsRegister());
1758     __ Cbnz(InputRegisterAt(instruction, 0), true_target);
1759   } else {
1760     // The condition instruction has not been materialized, use its inputs as
1761     // the comparison and its condition as the branch condition.
1762     Register lhs = InputRegisterAt(condition, 0);
1763     Operand rhs = InputOperandAt(condition, 1);
1764     Condition arm64_cond = ARM64Condition(condition->GetCondition());
1765     if ((arm64_cond != gt && arm64_cond != le) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
1766       switch (arm64_cond) {
1767         case eq:
1768           __ Cbz(lhs, true_target);
1769           break;
1770         case ne:
1771           __ Cbnz(lhs, true_target);
1772           break;
1773         case lt:
1774           // Test the sign bit and branch accordingly.
1775           __ Tbnz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, true_target);
1776           break;
1777         case ge:
1778           // Test the sign bit and branch accordingly.
1779           __ Tbz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, true_target);
1780           break;
1781         default:
1782           // Without the `static_cast` the compiler throws an error for
1783           // `-Werror=sign-promo`.
1784           LOG(FATAL) << "Unexpected condition: " << static_cast<int>(arm64_cond);
1785       }
1786     } else {
1787       __ Cmp(lhs, rhs);
1788       __ B(arm64_cond, true_target);
1789     }
1790   }
1791   if (false_target != nullptr) {
1792     __ B(false_target);
1793   }
1794 }
1795 
VisitIf(HIf * if_instr)1796 void LocationsBuilderARM64::VisitIf(HIf* if_instr) {
1797   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
1798   HInstruction* cond = if_instr->InputAt(0);
1799   if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1800     locations->SetInAt(0, Location::RequiresRegister());
1801   }
1802 }
1803 
VisitIf(HIf * if_instr)1804 void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) {
1805   vixl::Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1806   vixl::Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1807   vixl::Label* always_true_target = true_target;
1808   if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1809                                 if_instr->IfTrueSuccessor())) {
1810     always_true_target = nullptr;
1811   }
1812   if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1813                                 if_instr->IfFalseSuccessor())) {
1814     false_target = nullptr;
1815   }
1816   GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1817 }
1818 
VisitDeoptimize(HDeoptimize * deoptimize)1819 void LocationsBuilderARM64::VisitDeoptimize(HDeoptimize* deoptimize) {
1820   LocationSummary* locations = new (GetGraph()->GetArena())
1821       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1822   HInstruction* cond = deoptimize->InputAt(0);
1823   DCHECK(cond->IsCondition());
1824   if (cond->AsCondition()->NeedsMaterialization()) {
1825     locations->SetInAt(0, Location::RequiresRegister());
1826   }
1827 }
1828 
VisitDeoptimize(HDeoptimize * deoptimize)1829 void InstructionCodeGeneratorARM64::VisitDeoptimize(HDeoptimize* deoptimize) {
1830   SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena())
1831       DeoptimizationSlowPathARM64(deoptimize);
1832   codegen_->AddSlowPath(slow_path);
1833   vixl::Label* slow_path_entry = slow_path->GetEntryLabel();
1834   GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1835 }
1836 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)1837 void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1838   HandleFieldGet(instruction);
1839 }
1840 
VisitInstanceFieldGet(HInstanceFieldGet * instruction)1841 void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1842   HandleFieldGet(instruction, instruction->GetFieldInfo());
1843 }
1844 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)1845 void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1846   HandleFieldSet(instruction);
1847 }
1848 
VisitInstanceFieldSet(HInstanceFieldSet * instruction)1849 void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1850   HandleFieldSet(instruction, instruction->GetFieldInfo());
1851 }
1852 
VisitInstanceOf(HInstanceOf * instruction)1853 void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
1854   LocationSummary::CallKind call_kind =
1855       instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
1856   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
1857   locations->SetInAt(0, Location::RequiresRegister());
1858   locations->SetInAt(1, Location::RequiresRegister());
1859   // The output does overlap inputs.
1860   locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
1861 }
1862 
VisitInstanceOf(HInstanceOf * instruction)1863 void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
1864   LocationSummary* locations = instruction->GetLocations();
1865   Register obj = InputRegisterAt(instruction, 0);;
1866   Register cls = InputRegisterAt(instruction, 1);;
1867   Register out = OutputRegister(instruction);
1868 
1869   vixl::Label done;
1870 
1871   // Return 0 if `obj` is null.
1872   // Avoid null check if we know `obj` is not null.
1873   if (instruction->MustDoNullCheck()) {
1874     __ Mov(out, 0);
1875     __ Cbz(obj, &done);
1876   }
1877 
1878   // Compare the class of `obj` with `cls`.
1879   __ Ldr(out, HeapOperand(obj, mirror::Object::ClassOffset()));
1880   __ Cmp(out, cls);
1881   if (instruction->IsClassFinal()) {
1882     // Classes must be equal for the instanceof to succeed.
1883     __ Cset(out, eq);
1884   } else {
1885     // If the classes are not equal, we go into a slow path.
1886     DCHECK(locations->OnlyCallsOnSlowPath());
1887     SlowPathCodeARM64* slow_path =
1888         new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(
1889         instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
1890     codegen_->AddSlowPath(slow_path);
1891     __ B(ne, slow_path->GetEntryLabel());
1892     __ Mov(out, 1);
1893     __ Bind(slow_path->GetExitLabel());
1894   }
1895 
1896   __ Bind(&done);
1897 }
1898 
VisitIntConstant(HIntConstant * constant)1899 void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
1900   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1901   locations->SetOut(Location::ConstantLocation(constant));
1902 }
1903 
VisitIntConstant(HIntConstant * constant)1904 void InstructionCodeGeneratorARM64::VisitIntConstant(HIntConstant* constant) {
1905   // Will be generated at use site.
1906   UNUSED(constant);
1907 }
1908 
VisitNullConstant(HNullConstant * constant)1909 void LocationsBuilderARM64::VisitNullConstant(HNullConstant* constant) {
1910   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
1911   locations->SetOut(Location::ConstantLocation(constant));
1912 }
1913 
VisitNullConstant(HNullConstant * constant)1914 void InstructionCodeGeneratorARM64::VisitNullConstant(HNullConstant* constant) {
1915   // Will be generated at use site.
1916   UNUSED(constant);
1917 }
1918 
HandleInvoke(HInvoke * invoke)1919 void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
1920   LocationSummary* locations =
1921       new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
1922   locations->AddTemp(LocationFrom(x0));
1923 
1924   InvokeDexCallingConventionVisitorARM64 calling_convention_visitor;
1925   for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
1926     HInstruction* input = invoke->InputAt(i);
1927     locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1928   }
1929 
1930   Primitive::Type return_type = invoke->GetType();
1931   if (return_type != Primitive::kPrimVoid) {
1932     locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type));
1933   }
1934 }
1935 
VisitInvokeInterface(HInvokeInterface * invoke)1936 void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1937   HandleInvoke(invoke);
1938 }
1939 
VisitInvokeInterface(HInvokeInterface * invoke)1940 void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
1941   // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
1942   Register temp = XRegisterFrom(invoke->GetLocations()->GetTemp(0));
1943   uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1944       invoke->GetImtIndex() % mirror::Class::kImtSize, kArm64PointerSize).Uint32Value();
1945   Location receiver = invoke->GetLocations()->InAt(0);
1946   Offset class_offset = mirror::Object::ClassOffset();
1947   Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
1948 
1949   // The register ip1 is required to be used for the hidden argument in
1950   // art_quick_imt_conflict_trampoline, so prevent VIXL from using it.
1951   MacroAssembler* masm = GetVIXLAssembler();
1952   UseScratchRegisterScope scratch_scope(masm);
1953   BlockPoolsScope block_pools(masm);
1954   scratch_scope.Exclude(ip1);
1955   __ Mov(ip1, invoke->GetDexMethodIndex());
1956 
1957   // temp = object->GetClass();
1958   if (receiver.IsStackSlot()) {
1959     __ Ldr(temp.W(), StackOperandFrom(receiver));
1960     __ Ldr(temp.W(), HeapOperand(temp.W(), class_offset));
1961   } else {
1962     __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
1963   }
1964   codegen_->MaybeRecordImplicitNullCheck(invoke);
1965   // temp = temp->GetImtEntryAt(method_offset);
1966   __ Ldr(temp, MemOperand(temp, method_offset));
1967   // lr = temp->GetEntryPoint();
1968   __ Ldr(lr, MemOperand(temp, entry_point.Int32Value()));
1969   // lr();
1970   __ Blr(lr);
1971   DCHECK(!codegen_->IsLeafMethod());
1972   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1973 }
1974 
VisitInvokeVirtual(HInvokeVirtual * invoke)1975 void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1976   IntrinsicLocationsBuilderARM64 intrinsic(GetGraph()->GetArena());
1977   if (intrinsic.TryDispatch(invoke)) {
1978     return;
1979   }
1980 
1981   HandleInvoke(invoke);
1982 }
1983 
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)1984 void LocationsBuilderARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
1985   // When we do not run baseline, explicit clinit checks triggered by static
1986   // invokes must have been pruned by art::PrepareForRegisterAllocation.
1987   DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
1988 
1989   IntrinsicLocationsBuilderARM64 intrinsic(GetGraph()->GetArena());
1990   if (intrinsic.TryDispatch(invoke)) {
1991     return;
1992   }
1993 
1994   HandleInvoke(invoke);
1995 }
1996 
TryGenerateIntrinsicCode(HInvoke * invoke,CodeGeneratorARM64 * codegen)1997 static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM64* codegen) {
1998   if (invoke->GetLocations()->Intrinsified()) {
1999     IntrinsicCodeGeneratorARM64 intrinsic(codegen);
2000     intrinsic.Dispatch(invoke);
2001     return true;
2002   }
2003   return false;
2004 }
2005 
GenerateStaticOrDirectCall(HInvokeStaticOrDirect * invoke,Register temp)2006 void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) {
2007   // Make sure that ArtMethod* is passed in kArtMethodRegister as per the calling convention.
2008   DCHECK(temp.Is(kArtMethodRegister));
2009   size_t index_in_cache = GetCachePointerOffset(invoke->GetDexMethodIndex());
2010 
2011   // TODO: Implement all kinds of calls:
2012   // 1) boot -> boot
2013   // 2) app -> boot
2014   // 3) app -> app
2015   //
2016   // Currently we implement the app -> app logic, which looks up in the resolve cache.
2017 
2018   if (invoke->IsStringInit()) {
2019     // temp = thread->string_init_entrypoint
2020     __ Ldr(temp.X(), MemOperand(tr, invoke->GetStringInitOffset()));
2021     // LR = temp->entry_point_from_quick_compiled_code_;
2022     __ Ldr(lr, MemOperand(
2023         temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize).Int32Value()));
2024     // lr()
2025     __ Blr(lr);
2026   } else {
2027     // temp = method;
2028     LoadCurrentMethod(temp.X());
2029     if (!invoke->IsRecursive()) {
2030       // temp = temp->dex_cache_resolved_methods_;
2031       __ Ldr(temp.W(), MemOperand(temp.X(),
2032                                   ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
2033       // temp = temp[index_in_cache];
2034       __ Ldr(temp.X(), MemOperand(temp, index_in_cache));
2035       // lr = temp->entry_point_from_quick_compiled_code_;
2036       __ Ldr(lr, MemOperand(temp.X(), ArtMethod::EntryPointFromQuickCompiledCodeOffset(
2037           kArm64WordSize).Int32Value()));
2038       // lr();
2039       __ Blr(lr);
2040     } else {
2041       __ Bl(&frame_entry_label_);
2042     }
2043   }
2044 
2045   DCHECK(!IsLeafMethod());
2046 }
2047 
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)2048 void InstructionCodeGeneratorARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
2049   // When we do not run baseline, explicit clinit checks triggered by static
2050   // invokes must have been pruned by art::PrepareForRegisterAllocation.
2051   DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
2052 
2053   if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2054     return;
2055   }
2056 
2057   BlockPoolsScope block_pools(GetVIXLAssembler());
2058   Register temp = XRegisterFrom(invoke->GetLocations()->GetTemp(0));
2059   codegen_->GenerateStaticOrDirectCall(invoke, temp);
2060   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2061 }
2062 
VisitInvokeVirtual(HInvokeVirtual * invoke)2063 void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
2064   if (TryGenerateIntrinsicCode(invoke, codegen_)) {
2065     return;
2066   }
2067 
2068   LocationSummary* locations = invoke->GetLocations();
2069   Location receiver = locations->InAt(0);
2070   Register temp = XRegisterFrom(invoke->GetLocations()->GetTemp(0));
2071   size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
2072       invoke->GetVTableIndex(), kArm64PointerSize).SizeValue();
2073   Offset class_offset = mirror::Object::ClassOffset();
2074   Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
2075 
2076   BlockPoolsScope block_pools(GetVIXLAssembler());
2077 
2078   // temp = object->GetClass();
2079   if (receiver.IsStackSlot()) {
2080     __ Ldr(temp.W(), MemOperand(sp, receiver.GetStackIndex()));
2081     __ Ldr(temp.W(), HeapOperand(temp.W(), class_offset));
2082   } else {
2083     DCHECK(receiver.IsRegister());
2084     __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
2085   }
2086   codegen_->MaybeRecordImplicitNullCheck(invoke);
2087   // temp = temp->GetMethodAt(method_offset);
2088   __ Ldr(temp, MemOperand(temp, method_offset));
2089   // lr = temp->GetEntryPoint();
2090   __ Ldr(lr, MemOperand(temp, entry_point.SizeValue()));
2091   // lr();
2092   __ Blr(lr);
2093   DCHECK(!codegen_->IsLeafMethod());
2094   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
2095 }
2096 
VisitLoadClass(HLoadClass * cls)2097 void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
2098   LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
2099                                                               : LocationSummary::kNoCall;
2100   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
2101   locations->SetOut(Location::RequiresRegister());
2102 }
2103 
VisitLoadClass(HLoadClass * cls)2104 void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
2105   Register out = OutputRegister(cls);
2106   if (cls->IsReferrersClass()) {
2107     DCHECK(!cls->CanCallRuntime());
2108     DCHECK(!cls->MustGenerateClinitCheck());
2109     codegen_->LoadCurrentMethod(out.X());
2110     __ Ldr(out, MemOperand(out.X(), ArtMethod::DeclaringClassOffset().Int32Value()));
2111   } else {
2112     DCHECK(cls->CanCallRuntime());
2113     codegen_->LoadCurrentMethod(out.X());
2114     __ Ldr(out, MemOperand(out.X(), ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
2115     __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
2116 
2117     SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
2118         cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
2119     codegen_->AddSlowPath(slow_path);
2120     __ Cbz(out, slow_path->GetEntryLabel());
2121     if (cls->MustGenerateClinitCheck()) {
2122       GenerateClassInitializationCheck(slow_path, out);
2123     } else {
2124       __ Bind(slow_path->GetExitLabel());
2125     }
2126   }
2127 }
2128 
VisitLoadException(HLoadException * load)2129 void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
2130   LocationSummary* locations =
2131       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
2132   locations->SetOut(Location::RequiresRegister());
2133 }
2134 
VisitLoadException(HLoadException * instruction)2135 void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
2136   MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
2137   __ Ldr(OutputRegister(instruction), exception);
2138   __ Str(wzr, exception);
2139 }
2140 
VisitLoadLocal(HLoadLocal * load)2141 void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
2142   load->SetLocations(nullptr);
2143 }
2144 
VisitLoadLocal(HLoadLocal * load)2145 void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) {
2146   // Nothing to do, this is driven by the code generator.
2147   UNUSED(load);
2148 }
2149 
VisitLoadString(HLoadString * load)2150 void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
2151   LocationSummary* locations =
2152       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
2153   locations->SetOut(Location::RequiresRegister());
2154 }
2155 
VisitLoadString(HLoadString * load)2156 void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
2157   SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
2158   codegen_->AddSlowPath(slow_path);
2159 
2160   Register out = OutputRegister(load);
2161   codegen_->LoadCurrentMethod(out.X());
2162   __ Ldr(out, MemOperand(out.X(), ArtMethod::DeclaringClassOffset().Int32Value()));
2163   __ Ldr(out, HeapOperand(out, mirror::Class::DexCacheStringsOffset()));
2164   __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
2165   __ Cbz(out, slow_path->GetEntryLabel());
2166   __ Bind(slow_path->GetExitLabel());
2167 }
2168 
VisitLocal(HLocal * local)2169 void LocationsBuilderARM64::VisitLocal(HLocal* local) {
2170   local->SetLocations(nullptr);
2171 }
2172 
VisitLocal(HLocal * local)2173 void InstructionCodeGeneratorARM64::VisitLocal(HLocal* local) {
2174   DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
2175 }
2176 
VisitLongConstant(HLongConstant * constant)2177 void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
2178   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
2179   locations->SetOut(Location::ConstantLocation(constant));
2180 }
2181 
VisitLongConstant(HLongConstant * constant)2182 void InstructionCodeGeneratorARM64::VisitLongConstant(HLongConstant* constant) {
2183   // Will be generated at use site.
2184   UNUSED(constant);
2185 }
2186 
VisitMonitorOperation(HMonitorOperation * instruction)2187 void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
2188   LocationSummary* locations =
2189       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2190   InvokeRuntimeCallingConvention calling_convention;
2191   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2192 }
2193 
VisitMonitorOperation(HMonitorOperation * instruction)2194 void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
2195   codegen_->InvokeRuntime(instruction->IsEnter()
2196         ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
2197       instruction,
2198       instruction->GetDexPc(),
2199       nullptr);
2200   CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
2201 }
2202 
VisitMul(HMul * mul)2203 void LocationsBuilderARM64::VisitMul(HMul* mul) {
2204   LocationSummary* locations =
2205       new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2206   switch (mul->GetResultType()) {
2207     case Primitive::kPrimInt:
2208     case Primitive::kPrimLong:
2209       locations->SetInAt(0, Location::RequiresRegister());
2210       locations->SetInAt(1, Location::RequiresRegister());
2211       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2212       break;
2213 
2214     case Primitive::kPrimFloat:
2215     case Primitive::kPrimDouble:
2216       locations->SetInAt(0, Location::RequiresFpuRegister());
2217       locations->SetInAt(1, Location::RequiresFpuRegister());
2218       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2219       break;
2220 
2221     default:
2222       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2223   }
2224 }
2225 
VisitMul(HMul * mul)2226 void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) {
2227   switch (mul->GetResultType()) {
2228     case Primitive::kPrimInt:
2229     case Primitive::kPrimLong:
2230       __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1));
2231       break;
2232 
2233     case Primitive::kPrimFloat:
2234     case Primitive::kPrimDouble:
2235       __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1));
2236       break;
2237 
2238     default:
2239       LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
2240   }
2241 }
2242 
VisitNeg(HNeg * neg)2243 void LocationsBuilderARM64::VisitNeg(HNeg* neg) {
2244   LocationSummary* locations =
2245       new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
2246   switch (neg->GetResultType()) {
2247     case Primitive::kPrimInt:
2248     case Primitive::kPrimLong:
2249       locations->SetInAt(0, ARM64EncodableConstantOrRegister(neg->InputAt(0), neg));
2250       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2251       break;
2252 
2253     case Primitive::kPrimFloat:
2254     case Primitive::kPrimDouble:
2255       locations->SetInAt(0, Location::RequiresFpuRegister());
2256       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2257       break;
2258 
2259     default:
2260       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2261   }
2262 }
2263 
VisitNeg(HNeg * neg)2264 void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) {
2265   switch (neg->GetResultType()) {
2266     case Primitive::kPrimInt:
2267     case Primitive::kPrimLong:
2268       __ Neg(OutputRegister(neg), InputOperandAt(neg, 0));
2269       break;
2270 
2271     case Primitive::kPrimFloat:
2272     case Primitive::kPrimDouble:
2273       __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0));
2274       break;
2275 
2276     default:
2277       LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
2278   }
2279 }
2280 
VisitNewArray(HNewArray * instruction)2281 void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) {
2282   LocationSummary* locations =
2283       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2284   InvokeRuntimeCallingConvention calling_convention;
2285   locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
2286   locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(2)));
2287   locations->SetOut(LocationFrom(x0));
2288   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(1)));
2289   CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
2290                        void*, uint32_t, int32_t, ArtMethod*>();
2291 }
2292 
VisitNewArray(HNewArray * instruction)2293 void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) {
2294   LocationSummary* locations = instruction->GetLocations();
2295   InvokeRuntimeCallingConvention calling_convention;
2296   Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
2297   DCHECK(type_index.Is(w0));
2298   Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimLong);
2299   DCHECK(current_method.Is(x2));
2300   codegen_->LoadCurrentMethod(current_method.X());
2301   __ Mov(type_index, instruction->GetTypeIndex());
2302   codegen_->InvokeRuntime(
2303       GetThreadOffset<kArm64WordSize>(instruction->GetEntrypoint()).Int32Value(),
2304       instruction,
2305       instruction->GetDexPc(),
2306       nullptr);
2307   CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
2308 }
2309 
VisitNewInstance(HNewInstance * instruction)2310 void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
2311   LocationSummary* locations =
2312       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2313   InvokeRuntimeCallingConvention calling_convention;
2314   locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
2315   locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
2316   locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
2317   CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
2318 }
2319 
VisitNewInstance(HNewInstance * instruction)2320 void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) {
2321   LocationSummary* locations = instruction->GetLocations();
2322   Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
2323   DCHECK(type_index.Is(w0));
2324   Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
2325   DCHECK(current_method.Is(w1));
2326   codegen_->LoadCurrentMethod(current_method.X());
2327   __ Mov(type_index, instruction->GetTypeIndex());
2328   codegen_->InvokeRuntime(
2329       GetThreadOffset<kArm64WordSize>(instruction->GetEntrypoint()).Int32Value(),
2330       instruction,
2331       instruction->GetDexPc(),
2332       nullptr);
2333   CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
2334 }
2335 
VisitNot(HNot * instruction)2336 void LocationsBuilderARM64::VisitNot(HNot* instruction) {
2337   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2338   locations->SetInAt(0, Location::RequiresRegister());
2339   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2340 }
2341 
VisitNot(HNot * instruction)2342 void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
2343   switch (instruction->GetResultType()) {
2344     case Primitive::kPrimInt:
2345     case Primitive::kPrimLong:
2346       __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
2347       break;
2348 
2349     default:
2350       LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
2351   }
2352 }
2353 
VisitBooleanNot(HBooleanNot * instruction)2354 void LocationsBuilderARM64::VisitBooleanNot(HBooleanNot* instruction) {
2355   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2356   locations->SetInAt(0, Location::RequiresRegister());
2357   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2358 }
2359 
VisitBooleanNot(HBooleanNot * instruction)2360 void InstructionCodeGeneratorARM64::VisitBooleanNot(HBooleanNot* instruction) {
2361   __ Eor(OutputRegister(instruction), InputRegisterAt(instruction, 0), vixl::Operand(1));
2362 }
2363 
VisitNullCheck(HNullCheck * instruction)2364 void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
2365   LocationSummary* locations =
2366       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2367   locations->SetInAt(0, Location::RequiresRegister());
2368   if (instruction->HasUses()) {
2369     locations->SetOut(Location::SameAsFirstInput());
2370   }
2371 }
2372 
GenerateImplicitNullCheck(HNullCheck * instruction)2373 void InstructionCodeGeneratorARM64::GenerateImplicitNullCheck(HNullCheck* instruction) {
2374   if (codegen_->CanMoveNullCheckToUser(instruction)) {
2375     return;
2376   }
2377 
2378   BlockPoolsScope block_pools(GetVIXLAssembler());
2379   Location obj = instruction->GetLocations()->InAt(0);
2380   __ Ldr(wzr, HeapOperandFrom(obj, Offset(0)));
2381   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2382 }
2383 
GenerateExplicitNullCheck(HNullCheck * instruction)2384 void InstructionCodeGeneratorARM64::GenerateExplicitNullCheck(HNullCheck* instruction) {
2385   SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction);
2386   codegen_->AddSlowPath(slow_path);
2387 
2388   LocationSummary* locations = instruction->GetLocations();
2389   Location obj = locations->InAt(0);
2390 
2391   __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel());
2392 }
2393 
VisitNullCheck(HNullCheck * instruction)2394 void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
2395   if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
2396     GenerateImplicitNullCheck(instruction);
2397   } else {
2398     GenerateExplicitNullCheck(instruction);
2399   }
2400 }
2401 
VisitOr(HOr * instruction)2402 void LocationsBuilderARM64::VisitOr(HOr* instruction) {
2403   HandleBinaryOp(instruction);
2404 }
2405 
VisitOr(HOr * instruction)2406 void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) {
2407   HandleBinaryOp(instruction);
2408 }
2409 
VisitParallelMove(HParallelMove * instruction ATTRIBUTE_UNUSED)2410 void LocationsBuilderARM64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
2411   LOG(FATAL) << "Unreachable";
2412 }
2413 
VisitParallelMove(HParallelMove * instruction)2414 void InstructionCodeGeneratorARM64::VisitParallelMove(HParallelMove* instruction) {
2415   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
2416 }
2417 
VisitParameterValue(HParameterValue * instruction)2418 void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
2419   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2420   Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2421   if (location.IsStackSlot()) {
2422     location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2423   } else if (location.IsDoubleStackSlot()) {
2424     location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2425   }
2426   locations->SetOut(location);
2427 }
2428 
VisitParameterValue(HParameterValue * instruction)2429 void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) {
2430   // Nothing to do, the parameter is already at its location.
2431   UNUSED(instruction);
2432 }
2433 
VisitPhi(HPhi * instruction)2434 void LocationsBuilderARM64::VisitPhi(HPhi* instruction) {
2435   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2436   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2437     locations->SetInAt(i, Location::Any());
2438   }
2439   locations->SetOut(Location::Any());
2440 }
2441 
VisitPhi(HPhi * instruction)2442 void InstructionCodeGeneratorARM64::VisitPhi(HPhi* instruction) {
2443   UNUSED(instruction);
2444   LOG(FATAL) << "Unreachable";
2445 }
2446 
VisitRem(HRem * rem)2447 void LocationsBuilderARM64::VisitRem(HRem* rem) {
2448   Primitive::Type type = rem->GetResultType();
2449   LocationSummary::CallKind call_kind =
2450       Primitive::IsFloatingPointType(type) ? LocationSummary::kCall : LocationSummary::kNoCall;
2451   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
2452 
2453   switch (type) {
2454     case Primitive::kPrimInt:
2455     case Primitive::kPrimLong:
2456       locations->SetInAt(0, Location::RequiresRegister());
2457       locations->SetInAt(1, Location::RequiresRegister());
2458       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2459       break;
2460 
2461     case Primitive::kPrimFloat:
2462     case Primitive::kPrimDouble: {
2463       InvokeRuntimeCallingConvention calling_convention;
2464       locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
2465       locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1)));
2466       locations->SetOut(calling_convention.GetReturnLocation(type));
2467 
2468       break;
2469     }
2470 
2471     default:
2472       LOG(FATAL) << "Unexpected rem type " << type;
2473   }
2474 }
2475 
VisitRem(HRem * rem)2476 void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) {
2477   Primitive::Type type = rem->GetResultType();
2478 
2479   switch (type) {
2480     case Primitive::kPrimInt:
2481     case Primitive::kPrimLong: {
2482       UseScratchRegisterScope temps(GetVIXLAssembler());
2483       Register dividend = InputRegisterAt(rem, 0);
2484       Register divisor = InputRegisterAt(rem, 1);
2485       Register output = OutputRegister(rem);
2486       Register temp = temps.AcquireSameSizeAs(output);
2487 
2488       __ Sdiv(temp, dividend, divisor);
2489       __ Msub(output, temp, divisor, dividend);
2490       break;
2491     }
2492 
2493     case Primitive::kPrimFloat:
2494     case Primitive::kPrimDouble: {
2495       int32_t entry_offset = (type == Primitive::kPrimFloat) ? QUICK_ENTRY_POINT(pFmodf)
2496                                                              : QUICK_ENTRY_POINT(pFmod);
2497       codegen_->InvokeRuntime(entry_offset, rem, rem->GetDexPc(), nullptr);
2498       break;
2499     }
2500 
2501     default:
2502       LOG(FATAL) << "Unexpected rem type " << type;
2503   }
2504 }
2505 
VisitMemoryBarrier(HMemoryBarrier * memory_barrier)2506 void LocationsBuilderARM64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
2507   memory_barrier->SetLocations(nullptr);
2508 }
2509 
VisitMemoryBarrier(HMemoryBarrier * memory_barrier)2510 void InstructionCodeGeneratorARM64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
2511   GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
2512 }
2513 
VisitReturn(HReturn * instruction)2514 void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
2515   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2516   Primitive::Type return_type = instruction->InputAt(0)->GetType();
2517   locations->SetInAt(0, ARM64ReturnLocation(return_type));
2518 }
2519 
VisitReturn(HReturn * instruction)2520 void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) {
2521   UNUSED(instruction);
2522   codegen_->GenerateFrameExit();
2523 }
2524 
VisitReturnVoid(HReturnVoid * instruction)2525 void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) {
2526   instruction->SetLocations(nullptr);
2527 }
2528 
VisitReturnVoid(HReturnVoid * instruction)2529 void InstructionCodeGeneratorARM64::VisitReturnVoid(HReturnVoid* instruction) {
2530   UNUSED(instruction);
2531   codegen_->GenerateFrameExit();
2532 }
2533 
VisitShl(HShl * shl)2534 void LocationsBuilderARM64::VisitShl(HShl* shl) {
2535   HandleShift(shl);
2536 }
2537 
VisitShl(HShl * shl)2538 void InstructionCodeGeneratorARM64::VisitShl(HShl* shl) {
2539   HandleShift(shl);
2540 }
2541 
VisitShr(HShr * shr)2542 void LocationsBuilderARM64::VisitShr(HShr* shr) {
2543   HandleShift(shr);
2544 }
2545 
VisitShr(HShr * shr)2546 void InstructionCodeGeneratorARM64::VisitShr(HShr* shr) {
2547   HandleShift(shr);
2548 }
2549 
VisitStoreLocal(HStoreLocal * store)2550 void LocationsBuilderARM64::VisitStoreLocal(HStoreLocal* store) {
2551   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
2552   Primitive::Type field_type = store->InputAt(1)->GetType();
2553   switch (field_type) {
2554     case Primitive::kPrimNot:
2555     case Primitive::kPrimBoolean:
2556     case Primitive::kPrimByte:
2557     case Primitive::kPrimChar:
2558     case Primitive::kPrimShort:
2559     case Primitive::kPrimInt:
2560     case Primitive::kPrimFloat:
2561       locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
2562       break;
2563 
2564     case Primitive::kPrimLong:
2565     case Primitive::kPrimDouble:
2566       locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
2567       break;
2568 
2569     default:
2570       LOG(FATAL) << "Unimplemented local type " << field_type;
2571   }
2572 }
2573 
VisitStoreLocal(HStoreLocal * store)2574 void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) {
2575   UNUSED(store);
2576 }
2577 
VisitSub(HSub * instruction)2578 void LocationsBuilderARM64::VisitSub(HSub* instruction) {
2579   HandleBinaryOp(instruction);
2580 }
2581 
VisitSub(HSub * instruction)2582 void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
2583   HandleBinaryOp(instruction);
2584 }
2585 
VisitStaticFieldGet(HStaticFieldGet * instruction)2586 void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2587   HandleFieldGet(instruction);
2588 }
2589 
VisitStaticFieldGet(HStaticFieldGet * instruction)2590 void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2591   HandleFieldGet(instruction, instruction->GetFieldInfo());
2592 }
2593 
VisitStaticFieldSet(HStaticFieldSet * instruction)2594 void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2595   HandleFieldSet(instruction);
2596 }
2597 
VisitStaticFieldSet(HStaticFieldSet * instruction)2598 void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2599   HandleFieldSet(instruction, instruction->GetFieldInfo());
2600 }
2601 
VisitSuspendCheck(HSuspendCheck * instruction)2602 void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
2603   new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
2604 }
2605 
VisitSuspendCheck(HSuspendCheck * instruction)2606 void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
2607   HBasicBlock* block = instruction->GetBlock();
2608   if (block->GetLoopInformation() != nullptr) {
2609     DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
2610     // The back edge will generate the suspend check.
2611     return;
2612   }
2613   if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
2614     // The goto will generate the suspend check.
2615     return;
2616   }
2617   GenerateSuspendCheck(instruction, nullptr);
2618 }
2619 
VisitTemporary(HTemporary * temp)2620 void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
2621   temp->SetLocations(nullptr);
2622 }
2623 
VisitTemporary(HTemporary * temp)2624 void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) {
2625   // Nothing to do, this is driven by the code generator.
2626   UNUSED(temp);
2627 }
2628 
VisitThrow(HThrow * instruction)2629 void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
2630   LocationSummary* locations =
2631       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2632   InvokeRuntimeCallingConvention calling_convention;
2633   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
2634 }
2635 
VisitThrow(HThrow * instruction)2636 void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
2637   codegen_->InvokeRuntime(
2638       QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
2639   CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
2640 }
2641 
VisitTypeConversion(HTypeConversion * conversion)2642 void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
2643   LocationSummary* locations =
2644       new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
2645   Primitive::Type input_type = conversion->GetInputType();
2646   Primitive::Type result_type = conversion->GetResultType();
2647   DCHECK_NE(input_type, result_type);
2648   if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
2649       (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
2650     LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
2651   }
2652 
2653   if (Primitive::IsFloatingPointType(input_type)) {
2654     locations->SetInAt(0, Location::RequiresFpuRegister());
2655   } else {
2656     locations->SetInAt(0, Location::RequiresRegister());
2657   }
2658 
2659   if (Primitive::IsFloatingPointType(result_type)) {
2660     locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2661   } else {
2662     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2663   }
2664 }
2665 
VisitTypeConversion(HTypeConversion * conversion)2666 void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) {
2667   Primitive::Type result_type = conversion->GetResultType();
2668   Primitive::Type input_type = conversion->GetInputType();
2669 
2670   DCHECK_NE(input_type, result_type);
2671 
2672   if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
2673     int result_size = Primitive::ComponentSize(result_type);
2674     int input_size = Primitive::ComponentSize(input_type);
2675     int min_size = std::min(result_size, input_size);
2676     Register output = OutputRegister(conversion);
2677     Register source = InputRegisterAt(conversion, 0);
2678     if ((result_type == Primitive::kPrimChar) && (input_size < result_size)) {
2679       __ Ubfx(output, source, 0, result_size * kBitsPerByte);
2680     } else if ((result_type == Primitive::kPrimChar) ||
2681                ((input_type == Primitive::kPrimChar) && (result_size > input_size))) {
2682       __ Ubfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
2683     } else {
2684       __ Sbfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
2685     }
2686   } else if (Primitive::IsFloatingPointType(result_type) && Primitive::IsIntegralType(input_type)) {
2687     __ Scvtf(OutputFPRegister(conversion), InputRegisterAt(conversion, 0));
2688   } else if (Primitive::IsIntegralType(result_type) && Primitive::IsFloatingPointType(input_type)) {
2689     CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
2690     __ Fcvtzs(OutputRegister(conversion), InputFPRegisterAt(conversion, 0));
2691   } else if (Primitive::IsFloatingPointType(result_type) &&
2692              Primitive::IsFloatingPointType(input_type)) {
2693     __ Fcvt(OutputFPRegister(conversion), InputFPRegisterAt(conversion, 0));
2694   } else {
2695     LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
2696                 << " to " << result_type;
2697   }
2698 }
2699 
VisitUShr(HUShr * ushr)2700 void LocationsBuilderARM64::VisitUShr(HUShr* ushr) {
2701   HandleShift(ushr);
2702 }
2703 
VisitUShr(HUShr * ushr)2704 void InstructionCodeGeneratorARM64::VisitUShr(HUShr* ushr) {
2705   HandleShift(ushr);
2706 }
2707 
VisitXor(HXor * instruction)2708 void LocationsBuilderARM64::VisitXor(HXor* instruction) {
2709   HandleBinaryOp(instruction);
2710 }
2711 
VisitXor(HXor * instruction)2712 void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) {
2713   HandleBinaryOp(instruction);
2714 }
2715 
VisitBoundType(HBoundType * instruction)2716 void LocationsBuilderARM64::VisitBoundType(HBoundType* instruction) {
2717   // Nothing to do, this should be removed during prepare for register allocator.
2718   UNUSED(instruction);
2719   LOG(FATAL) << "Unreachable";
2720 }
2721 
VisitBoundType(HBoundType * instruction)2722 void InstructionCodeGeneratorARM64::VisitBoundType(HBoundType* instruction) {
2723   // Nothing to do, this should be removed during prepare for register allocator.
2724   UNUSED(instruction);
2725   LOG(FATAL) << "Unreachable";
2726 }
2727 
2728 #undef __
2729 #undef QUICK_ENTRY_POINT
2730 
2731 }  // namespace arm64
2732 }  // namespace art
2733