• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM64_H_
18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM64_H_
19 
20 #include "base/bit_field.h"
21 #include "class_root.h"
22 #include "code_generator.h"
23 #include "common_arm64.h"
24 #include "dex/dex_file_types.h"
25 #include "dex/string_reference.h"
26 #include "dex/type_reference.h"
27 #include "driver/compiler_options.h"
28 #include "nodes.h"
29 #include "parallel_move_resolver.h"
30 #include "utils/arm64/assembler_arm64.h"
31 
32 // TODO(VIXL): Make VIXL compile with -Wshadow.
33 #pragma GCC diagnostic push
34 #pragma GCC diagnostic ignored "-Wshadow"
35 #include "aarch64/disasm-aarch64.h"
36 #include "aarch64/macro-assembler-aarch64.h"
37 #pragma GCC diagnostic pop
38 
39 namespace art {
40 
41 namespace linker {
42 class Arm64RelativePatcherTest;
43 }  // namespace linker
44 
45 namespace arm64 {
46 
47 class CodeGeneratorARM64;
48 
49 // Use a local definition to prevent copying mistakes.
50 static constexpr size_t kArm64WordSize = static_cast<size_t>(kArm64PointerSize);
51 
52 // These constants are used as an approximate margin when emission of veneer and literal pools
53 // must be blocked.
54 static constexpr int kMaxMacroInstructionSizeInBytes = 15 * vixl::aarch64::kInstructionSize;
55 static constexpr int kInvokeCodeMarginSizeInBytes = 6 * kMaxMacroInstructionSizeInBytes;
56 
57 static const vixl::aarch64::Register kParameterCoreRegisters[] = {
58   vixl::aarch64::x1,
59   vixl::aarch64::x2,
60   vixl::aarch64::x3,
61   vixl::aarch64::x4,
62   vixl::aarch64::x5,
63   vixl::aarch64::x6,
64   vixl::aarch64::x7
65 };
66 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
67 static const vixl::aarch64::VRegister kParameterFPRegisters[] = {
68   vixl::aarch64::d0,
69   vixl::aarch64::d1,
70   vixl::aarch64::d2,
71   vixl::aarch64::d3,
72   vixl::aarch64::d4,
73   vixl::aarch64::d5,
74   vixl::aarch64::d6,
75   vixl::aarch64::d7
76 };
77 static constexpr size_t kParameterFPRegistersLength = arraysize(kParameterFPRegisters);
78 
79 // Thread Register.
80 const vixl::aarch64::Register tr = vixl::aarch64::x19;
81 // Marking Register.
82 const vixl::aarch64::Register mr = vixl::aarch64::x20;
83 // Implicit suspend check register.
84 const vixl::aarch64::Register kImplicitSuspendCheckRegister = vixl::aarch64::x21;
85 // Method register on invoke.
86 static const vixl::aarch64::Register kArtMethodRegister = vixl::aarch64::x0;
87 const vixl::aarch64::CPURegList vixl_reserved_core_registers(vixl::aarch64::ip0,
88                                                              vixl::aarch64::ip1);
89 const vixl::aarch64::CPURegList vixl_reserved_fp_registers(vixl::aarch64::d31);
90 
91 const vixl::aarch64::CPURegList runtime_reserved_core_registers =
92     vixl::aarch64::CPURegList(
93         tr,
94         // Reserve X20 as Marking Register when emitting Baker read barriers.
95         ((kEmitCompilerReadBarrier && kUseBakerReadBarrier) ? mr : vixl::aarch64::NoCPUReg),
96         kImplicitSuspendCheckRegister,
97         vixl::aarch64::lr);
98 
99 // Some instructions have special requirements for a temporary, for example
100 // LoadClass/kBssEntry and LoadString/kBssEntry for Baker read barrier require
101 // temp that's not an R0 (to avoid an extra move) and Baker read barrier field
102 // loads with large offsets need a fixed register to limit the number of link-time
103 // thunks we generate. For these and similar cases, we want to reserve a specific
104 // register that's neither callee-save nor an argument register. We choose x15.
FixedTempLocation()105 inline Location FixedTempLocation() {
106   return Location::RegisterLocation(vixl::aarch64::x15.GetCode());
107 }
108 
109 // Callee-save registers AAPCS64, without x19 (Thread Register) (nor
110 // x20 (Marking Register) when emitting Baker read barriers).
111 const vixl::aarch64::CPURegList callee_saved_core_registers(
112     vixl::aarch64::CPURegister::kRegister,
113     vixl::aarch64::kXRegSize,
114     ((kEmitCompilerReadBarrier && kUseBakerReadBarrier)
115          ? vixl::aarch64::x21.GetCode()
116          : vixl::aarch64::x20.GetCode()),
117      vixl::aarch64::x30.GetCode());
118 const vixl::aarch64::CPURegList callee_saved_fp_registers(vixl::aarch64::CPURegister::kVRegister,
119                                                           vixl::aarch64::kDRegSize,
120                                                           vixl::aarch64::d8.GetCode(),
121                                                           vixl::aarch64::d15.GetCode());
122 Location ARM64ReturnLocation(DataType::Type return_type);
123 
124 class SlowPathCodeARM64 : public SlowPathCode {
125  public:
SlowPathCodeARM64(HInstruction * instruction)126   explicit SlowPathCodeARM64(HInstruction* instruction)
127       : SlowPathCode(instruction), entry_label_(), exit_label_() {}
128 
GetEntryLabel()129   vixl::aarch64::Label* GetEntryLabel() { return &entry_label_; }
GetExitLabel()130   vixl::aarch64::Label* GetExitLabel() { return &exit_label_; }
131 
132   void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) override;
133   void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) override;
134 
135  private:
136   vixl::aarch64::Label entry_label_;
137   vixl::aarch64::Label exit_label_;
138 
139   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM64);
140 };
141 
142 class JumpTableARM64 : public DeletableArenaObject<kArenaAllocSwitchTable> {
143  public:
JumpTableARM64(HPackedSwitch * switch_instr)144   explicit JumpTableARM64(HPackedSwitch* switch_instr)
145     : switch_instr_(switch_instr), table_start_() {}
146 
GetTableStartLabel()147   vixl::aarch64::Label* GetTableStartLabel() { return &table_start_; }
148 
149   void EmitTable(CodeGeneratorARM64* codegen);
150 
151  private:
152   HPackedSwitch* const switch_instr_;
153   vixl::aarch64::Label table_start_;
154 
155   DISALLOW_COPY_AND_ASSIGN(JumpTableARM64);
156 };
157 
158 static const vixl::aarch64::Register kRuntimeParameterCoreRegisters[] =
159     { vixl::aarch64::x0,
160       vixl::aarch64::x1,
161       vixl::aarch64::x2,
162       vixl::aarch64::x3,
163       vixl::aarch64::x4,
164       vixl::aarch64::x5,
165       vixl::aarch64::x6,
166       vixl::aarch64::x7 };
167 static constexpr size_t kRuntimeParameterCoreRegistersLength =
168     arraysize(kRuntimeParameterCoreRegisters);
169 static const vixl::aarch64::VRegister kRuntimeParameterFpuRegisters[] =
170     { vixl::aarch64::d0,
171       vixl::aarch64::d1,
172       vixl::aarch64::d2,
173       vixl::aarch64::d3,
174       vixl::aarch64::d4,
175       vixl::aarch64::d5,
176       vixl::aarch64::d6,
177       vixl::aarch64::d7 };
178 static constexpr size_t kRuntimeParameterFpuRegistersLength =
179     arraysize(kRuntimeParameterCoreRegisters);
180 
181 class InvokeRuntimeCallingConvention : public CallingConvention<vixl::aarch64::Register,
182                                                                 vixl::aarch64::VRegister> {
183  public:
184   static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
185 
InvokeRuntimeCallingConvention()186   InvokeRuntimeCallingConvention()
187       : CallingConvention(kRuntimeParameterCoreRegisters,
188                           kRuntimeParameterCoreRegistersLength,
189                           kRuntimeParameterFpuRegisters,
190                           kRuntimeParameterFpuRegistersLength,
191                           kArm64PointerSize) {}
192 
193   Location GetReturnLocation(DataType::Type return_type);
194 
195  private:
196   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
197 };
198 
199 class InvokeDexCallingConvention : public CallingConvention<vixl::aarch64::Register,
200                                                             vixl::aarch64::VRegister> {
201  public:
InvokeDexCallingConvention()202   InvokeDexCallingConvention()
203       : CallingConvention(kParameterCoreRegisters,
204                           kParameterCoreRegistersLength,
205                           kParameterFPRegisters,
206                           kParameterFPRegistersLength,
207                           kArm64PointerSize) {}
208 
GetReturnLocation(DataType::Type return_type)209   Location GetReturnLocation(DataType::Type return_type) const {
210     return ARM64ReturnLocation(return_type);
211   }
212 
213 
214  private:
215   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
216 };
217 
218 class InvokeDexCallingConventionVisitorARM64 : public InvokeDexCallingConventionVisitor {
219  public:
InvokeDexCallingConventionVisitorARM64()220   InvokeDexCallingConventionVisitorARM64() {}
~InvokeDexCallingConventionVisitorARM64()221   virtual ~InvokeDexCallingConventionVisitorARM64() {}
222 
223   Location GetNextLocation(DataType::Type type) override;
GetReturnLocation(DataType::Type return_type)224   Location GetReturnLocation(DataType::Type return_type) const override {
225     return calling_convention.GetReturnLocation(return_type);
226   }
227   Location GetMethodLocation() const override;
228 
229  private:
230   InvokeDexCallingConvention calling_convention;
231 
232   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorARM64);
233 };
234 
235 class CriticalNativeCallingConventionVisitorARM64 : public InvokeDexCallingConventionVisitor {
236  public:
CriticalNativeCallingConventionVisitorARM64(bool for_register_allocation)237   explicit CriticalNativeCallingConventionVisitorARM64(bool for_register_allocation)
238       : for_register_allocation_(for_register_allocation) {}
239 
~CriticalNativeCallingConventionVisitorARM64()240   virtual ~CriticalNativeCallingConventionVisitorARM64() {}
241 
242   Location GetNextLocation(DataType::Type type) override;
243   Location GetReturnLocation(DataType::Type type) const override;
244   Location GetMethodLocation() const override;
245 
GetStackOffset()246   size_t GetStackOffset() const { return stack_offset_; }
247 
248  private:
249   // Register allocator does not support adjusting frame size, so we cannot provide final locations
250   // of stack arguments for register allocation. We ask the register allocator for any location and
251   // move these arguments to the right place after adjusting the SP when generating the call.
252   const bool for_register_allocation_;
253   size_t gpr_index_ = 0u;
254   size_t fpr_index_ = 0u;
255   size_t stack_offset_ = 0u;
256 
257   DISALLOW_COPY_AND_ASSIGN(CriticalNativeCallingConventionVisitorARM64);
258 };
259 
260 class FieldAccessCallingConventionARM64 : public FieldAccessCallingConvention {
261  public:
FieldAccessCallingConventionARM64()262   FieldAccessCallingConventionARM64() {}
263 
GetObjectLocation()264   Location GetObjectLocation() const override {
265     return helpers::LocationFrom(vixl::aarch64::x1);
266   }
GetFieldIndexLocation()267   Location GetFieldIndexLocation() const override {
268     return helpers::LocationFrom(vixl::aarch64::x0);
269   }
GetReturnLocation(DataType::Type type ATTRIBUTE_UNUSED)270   Location GetReturnLocation(DataType::Type type ATTRIBUTE_UNUSED) const override {
271     return helpers::LocationFrom(vixl::aarch64::x0);
272   }
GetSetValueLocation(DataType::Type type ATTRIBUTE_UNUSED,bool is_instance)273   Location GetSetValueLocation(DataType::Type type ATTRIBUTE_UNUSED,
274                                bool is_instance) const override {
275     return is_instance
276         ? helpers::LocationFrom(vixl::aarch64::x2)
277         : helpers::LocationFrom(vixl::aarch64::x1);
278   }
GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED)279   Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const override {
280     return helpers::LocationFrom(vixl::aarch64::d0);
281   }
282 
283  private:
284   DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionARM64);
285 };
286 
287 class InstructionCodeGeneratorARM64 : public InstructionCodeGenerator {
288  public:
289   InstructionCodeGeneratorARM64(HGraph* graph, CodeGeneratorARM64* codegen);
290 
291 #define DECLARE_VISIT_INSTRUCTION(name, super) \
292   void Visit##name(H##name* instr) override;
293 
294   FOR_EACH_CONCRETE_INSTRUCTION_SCALAR_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION)295   FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION)
296   FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION)
297 
298 #undef DECLARE_VISIT_INSTRUCTION
299 
300   void VisitInstruction(HInstruction* instruction) override {
301     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
302                << " (id " << instruction->GetId() << ")";
303   }
304 
GetAssembler()305   Arm64Assembler* GetAssembler() const { return assembler_; }
GetVIXLAssembler()306   vixl::aarch64::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); }
307 
308   // SIMD helpers.
309   virtual Location AllocateSIMDScratchLocation(vixl::aarch64::UseScratchRegisterScope* scope) = 0;
310   virtual void FreeSIMDScratchLocation(Location loc,
311                                        vixl::aarch64::UseScratchRegisterScope* scope)  = 0;
312   virtual void LoadSIMDRegFromStack(Location destination, Location source) = 0;
313   virtual void MoveSIMDRegToSIMDReg(Location destination, Location source) = 0;
314   virtual void MoveToSIMDStackSlot(Location destination, Location source) = 0;
315   virtual void SaveLiveRegistersHelper(LocationSummary* locations,
316                                        int64_t spill_offset) = 0;
317   virtual void RestoreLiveRegistersHelper(LocationSummary* locations,
318                                           int64_t spill_offset) = 0;
319 
320  protected:
321   void GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
322                                         vixl::aarch64::Register class_reg);
323   void GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check,
324                                          vixl::aarch64::Register temp);
325   void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
326   void HandleBinaryOp(HBinaryOperation* instr);
327 
328   void HandleFieldSet(HInstruction* instruction,
329                       const FieldInfo& field_info,
330                       bool value_can_be_null);
331   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
332   void HandleCondition(HCondition* instruction);
333 
334   // Generate a heap reference load using one register `out`:
335   //
336   //   out <- *(out + offset)
337   //
338   // while honoring heap poisoning and/or read barriers (if any).
339   //
340   // Location `maybe_temp` is used when generating a read barrier and
341   // shall be a register in that case; it may be an invalid location
342   // otherwise.
343   void GenerateReferenceLoadOneRegister(HInstruction* instruction,
344                                         Location out,
345                                         uint32_t offset,
346                                         Location maybe_temp,
347                                         ReadBarrierOption read_barrier_option);
348   // Generate a heap reference load using two different registers
349   // `out` and `obj`:
350   //
351   //   out <- *(obj + offset)
352   //
353   // while honoring heap poisoning and/or read barriers (if any).
354   //
355   // Location `maybe_temp` is used when generating a Baker's (fast
356   // path) read barrier and shall be a register in that case; it may
357   // be an invalid location otherwise.
358   void GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
359                                          Location out,
360                                          Location obj,
361                                          uint32_t offset,
362                                          Location maybe_temp,
363                                          ReadBarrierOption read_barrier_option);
364 
365   // Generate a floating-point comparison.
366   void GenerateFcmp(HInstruction* instruction);
367 
368   void HandleShift(HBinaryOperation* instr);
369   void GenerateTestAndBranch(HInstruction* instruction,
370                              size_t condition_input_index,
371                              vixl::aarch64::Label* true_target,
372                              vixl::aarch64::Label* false_target);
373   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
374   void DivRemByPowerOfTwo(HBinaryOperation* instruction);
375   void GenerateIncrementNegativeByOne(vixl::aarch64::Register out,
376                                       vixl::aarch64::Register in, bool use_cond_inc);
377   void GenerateResultRemWithAnyConstant(vixl::aarch64::Register out,
378                                         vixl::aarch64::Register dividend,
379                                         vixl::aarch64::Register quotient,
380                                         int64_t divisor,
381                                         // This function may acquire a scratch register.
382                                         vixl::aarch64::UseScratchRegisterScope* temps_scope);
383   void GenerateInt64UnsignedDivRemWithAnyPositiveConstant(HBinaryOperation* instruction);
384   void GenerateInt64DivRemWithAnyConstant(HBinaryOperation* instruction);
385   void GenerateInt32DivRemWithAnyConstant(HBinaryOperation* instruction);
386   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction, int64_t divisor);
387   void GenerateIntDiv(HDiv* instruction);
388   void GenerateIntDivForConstDenom(HDiv *instruction);
389   void GenerateIntDivForPower2Denom(HDiv *instruction);
390   void GenerateIntRem(HRem* instruction);
391   void GenerateIntRemForConstDenom(HRem *instruction);
392   void GenerateIntRemForPower2Denom(HRem *instruction);
393   void HandleGoto(HInstruction* got, HBasicBlock* successor);
394   void GenerateMethodEntryExitHook(HInstruction* instruction);
395 
396   // Helpers to set up locations for vector memory operations. Returns the memory operand and,
397   // if used, sets the output parameter scratch to a temporary register used in this operand,
398   // so that the client can release it right after the memory operand use.
399   // Neon version.
400   vixl::aarch64::MemOperand VecNEONAddress(
401       HVecMemoryOperation* instruction,
402       // This function may acquire a scratch register.
403       vixl::aarch64::UseScratchRegisterScope* temps_scope,
404       size_t size,
405       bool is_string_char_at,
406       /*out*/ vixl::aarch64::Register* scratch);
407   // SVE version.
408   vixl::aarch64::SVEMemOperand VecSVEAddress(
409       HVecMemoryOperation* instruction,
410       // This function may acquire a scratch register.
411       vixl::aarch64::UseScratchRegisterScope* temps_scope,
412       size_t size,
413       bool is_string_char_at,
414       /*out*/ vixl::aarch64::Register* scratch);
415 
416   Arm64Assembler* const assembler_;
417   CodeGeneratorARM64* const codegen_;
418 
419   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorARM64);
420 };
421 
422 class LocationsBuilderARM64 : public HGraphVisitor {
423  public:
LocationsBuilderARM64(HGraph * graph,CodeGeneratorARM64 * codegen)424   LocationsBuilderARM64(HGraph* graph, CodeGeneratorARM64* codegen)
425       : HGraphVisitor(graph), codegen_(codegen) {}
426 
427 #define DECLARE_VISIT_INSTRUCTION(name, super) \
428   void Visit##name(H##name* instr) override;
429 
430   FOR_EACH_CONCRETE_INSTRUCTION_SCALAR_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION)431   FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION)
432   FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION)
433 
434 #undef DECLARE_VISIT_INSTRUCTION
435 
436   void VisitInstruction(HInstruction* instruction) override {
437     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
438                << " (id " << instruction->GetId() << ")";
439   }
440 
441  protected:
442   void HandleBinaryOp(HBinaryOperation* instr);
443   void HandleFieldSet(HInstruction* instruction);
444   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
445   void HandleInvoke(HInvoke* instr);
446   void HandleCondition(HCondition* instruction);
447   void HandleShift(HBinaryOperation* instr);
448 
449   CodeGeneratorARM64* const codegen_;
450   InvokeDexCallingConventionVisitorARM64 parameter_visitor_;
451 
452   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM64);
453 };
454 
455 class InstructionCodeGeneratorARM64Neon : public InstructionCodeGeneratorARM64 {
456  public:
InstructionCodeGeneratorARM64Neon(HGraph * graph,CodeGeneratorARM64 * codegen)457   InstructionCodeGeneratorARM64Neon(HGraph* graph, CodeGeneratorARM64* codegen) :
458       InstructionCodeGeneratorARM64(graph, codegen) {}
459 
460 #define DECLARE_VISIT_INSTRUCTION(name, super) \
461   void Visit##name(H##name* instr) override;
462 
463   FOR_EACH_CONCRETE_INSTRUCTION_VECTOR_COMMON(DECLARE_VISIT_INSTRUCTION)
464 
465 #undef DECLARE_VISIT_INSTRUCTION
466 
467   Location AllocateSIMDScratchLocation(vixl::aarch64::UseScratchRegisterScope* scope) override;
468   void FreeSIMDScratchLocation(Location loc,
469                                vixl::aarch64::UseScratchRegisterScope* scope) override;
470   void LoadSIMDRegFromStack(Location destination, Location source) override;
471   void MoveSIMDRegToSIMDReg(Location destination, Location source) override;
472   void MoveToSIMDStackSlot(Location destination, Location source) override;
473   void SaveLiveRegistersHelper(LocationSummary* locations, int64_t spill_offset) override;
474   void RestoreLiveRegistersHelper(LocationSummary* locations, int64_t spill_offset) override;
475 };
476 
477 class LocationsBuilderARM64Neon : public LocationsBuilderARM64 {
478  public:
LocationsBuilderARM64Neon(HGraph * graph,CodeGeneratorARM64 * codegen)479   LocationsBuilderARM64Neon(HGraph* graph, CodeGeneratorARM64* codegen) :
480       LocationsBuilderARM64(graph, codegen) {}
481 
482 #define DECLARE_VISIT_INSTRUCTION(name, super) \
483   void Visit##name(H##name* instr) override;
484 
485   FOR_EACH_CONCRETE_INSTRUCTION_VECTOR_COMMON(DECLARE_VISIT_INSTRUCTION)
486 
487 #undef DECLARE_VISIT_INSTRUCTION
488 };
489 
490 class InstructionCodeGeneratorARM64Sve : public InstructionCodeGeneratorARM64 {
491  public:
InstructionCodeGeneratorARM64Sve(HGraph * graph,CodeGeneratorARM64 * codegen)492   InstructionCodeGeneratorARM64Sve(HGraph* graph, CodeGeneratorARM64* codegen) :
493       InstructionCodeGeneratorARM64(graph, codegen) {}
494 
495 #define DECLARE_VISIT_INSTRUCTION(name, super) \
496   void Visit##name(H##name* instr) override;
497 
498   FOR_EACH_CONCRETE_INSTRUCTION_VECTOR_COMMON(DECLARE_VISIT_INSTRUCTION)
499 
500 #undef DECLARE_VISIT_INSTRUCTION
501 
502   Location AllocateSIMDScratchLocation(vixl::aarch64::UseScratchRegisterScope* scope) override;
503   void FreeSIMDScratchLocation(Location loc,
504                                vixl::aarch64::UseScratchRegisterScope* scope) override;
505   void LoadSIMDRegFromStack(Location destination, Location source) override;
506   void MoveSIMDRegToSIMDReg(Location destination, Location source) override;
507   void MoveToSIMDStackSlot(Location destination, Location source) override;
508   void SaveLiveRegistersHelper(LocationSummary* locations, int64_t spill_offset) override;
509   void RestoreLiveRegistersHelper(LocationSummary* locations, int64_t spill_offset) override;
510 
511  private:
512   // Validate that instruction vector length and packed type are compliant with the SIMD
513   // register size (full SIMD register is used).
514   void ValidateVectorLength(HVecOperation* instr) const;
515 
516   // Returns default predicate register which is used as governing vector predicate
517   // to implement predicated loop execution.
518   //
519   // TODO: This is a hack to be addressed when register allocator supports SIMD types.
LoopPReg()520   static vixl::aarch64::PRegister LoopPReg() {
521     return vixl::aarch64::p0;
522   }
523 };
524 
525 class LocationsBuilderARM64Sve : public LocationsBuilderARM64 {
526  public:
LocationsBuilderARM64Sve(HGraph * graph,CodeGeneratorARM64 * codegen)527   LocationsBuilderARM64Sve(HGraph* graph, CodeGeneratorARM64* codegen) :
528       LocationsBuilderARM64(graph, codegen) {}
529 
530 #define DECLARE_VISIT_INSTRUCTION(name, super) \
531   void Visit##name(H##name* instr) override;
532 
533   FOR_EACH_CONCRETE_INSTRUCTION_VECTOR_COMMON(DECLARE_VISIT_INSTRUCTION)
534 
535 #undef DECLARE_VISIT_INSTRUCTION
536 };
537 
538 class ParallelMoveResolverARM64 : public ParallelMoveResolverNoSwap {
539  public:
ParallelMoveResolverARM64(ArenaAllocator * allocator,CodeGeneratorARM64 * codegen)540   ParallelMoveResolverARM64(ArenaAllocator* allocator, CodeGeneratorARM64* codegen)
541       : ParallelMoveResolverNoSwap(allocator), codegen_(codegen), vixl_temps_() {}
542 
543  protected:
544   void PrepareForEmitNativeCode() override;
545   void FinishEmitNativeCode() override;
546   Location AllocateScratchLocationFor(Location::Kind kind) override;
547   void FreeScratchLocation(Location loc) override;
548   void EmitMove(size_t index) override;
549 
550  private:
551   Arm64Assembler* GetAssembler() const;
GetVIXLAssembler()552   vixl::aarch64::MacroAssembler* GetVIXLAssembler() const {
553     return GetAssembler()->GetVIXLAssembler();
554   }
555 
556   CodeGeneratorARM64* const codegen_;
557   vixl::aarch64::UseScratchRegisterScope vixl_temps_;
558 
559   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverARM64);
560 };
561 
562 class CodeGeneratorARM64 : public CodeGenerator {
563  public:
564   CodeGeneratorARM64(HGraph* graph,
565                      const CompilerOptions& compiler_options,
566                      OptimizingCompilerStats* stats = nullptr);
~CodeGeneratorARM64()567   virtual ~CodeGeneratorARM64() {}
568 
569   void GenerateFrameEntry() override;
570   void GenerateFrameExit() override;
571 
572   vixl::aarch64::CPURegList GetFramePreservedCoreRegisters() const;
573   vixl::aarch64::CPURegList GetFramePreservedFPRegisters() const;
574 
575   void Bind(HBasicBlock* block) override;
576 
GetLabelOf(HBasicBlock * block)577   vixl::aarch64::Label* GetLabelOf(HBasicBlock* block) {
578     block = FirstNonEmptyBlock(block);
579     return &(block_labels_[block->GetBlockId()]);
580   }
581 
GetWordSize()582   size_t GetWordSize() const override {
583     return kArm64WordSize;
584   }
585 
SupportsPredicatedSIMD()586   bool SupportsPredicatedSIMD() const override { return ShouldUseSVE(); }
587 
GetSlowPathFPWidth()588   size_t GetSlowPathFPWidth() const override {
589     return GetGraph()->HasSIMD()
590         ? GetSIMDRegisterWidth()
591         : vixl::aarch64::kDRegSizeInBytes;
592   }
593 
GetCalleePreservedFPWidth()594   size_t GetCalleePreservedFPWidth() const override {
595     return vixl::aarch64::kDRegSizeInBytes;
596   }
597 
598   size_t GetSIMDRegisterWidth() const override;
599 
GetAddressOf(HBasicBlock * block)600   uintptr_t GetAddressOf(HBasicBlock* block) override {
601     vixl::aarch64::Label* block_entry_label = GetLabelOf(block);
602     DCHECK(block_entry_label->IsBound());
603     return block_entry_label->GetLocation();
604   }
605 
GetLocationBuilder()606   HGraphVisitor* GetLocationBuilder() override { return location_builder_; }
GetInstructionCodeGeneratorArm64()607   InstructionCodeGeneratorARM64* GetInstructionCodeGeneratorArm64() {
608     return instruction_visitor_;
609   }
GetInstructionVisitor()610   HGraphVisitor* GetInstructionVisitor() override { return GetInstructionCodeGeneratorArm64(); }
GetAssembler()611   Arm64Assembler* GetAssembler() override { return &assembler_; }
GetAssembler()612   const Arm64Assembler& GetAssembler() const override { return assembler_; }
GetVIXLAssembler()613   vixl::aarch64::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); }
614 
615   // Emit a write barrier.
616   void MarkGCCard(vixl::aarch64::Register object,
617                   vixl::aarch64::Register value,
618                   bool value_can_be_null);
619 
620   void GenerateMemoryBarrier(MemBarrierKind kind);
621 
622   // Register allocation.
623 
624   void SetupBlockedRegisters() const override;
625 
626   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) override;
627   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) override;
628   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) override;
629   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) override;
630 
631   // The number of registers that can be allocated. The register allocator may
632   // decide to reserve and not use a few of them.
633   // We do not consider registers sp, xzr, wzr. They are either not allocatable
634   // (xzr, wzr), or make for poor allocatable registers (sp alignment
635   // requirements, etc.). This also facilitates our task as all other registers
636   // can easily be mapped via to or from their type and index or code.
637   static const int kNumberOfAllocatableRegisters = vixl::aarch64::kNumberOfRegisters - 1;
638   static const int kNumberOfAllocatableFPRegisters = vixl::aarch64::kNumberOfVRegisters;
639   static constexpr int kNumberOfAllocatableRegisterPairs = 0;
640 
641   void DumpCoreRegister(std::ostream& stream, int reg) const override;
642   void DumpFloatingPointRegister(std::ostream& stream, int reg) const override;
643 
GetInstructionSet()644   InstructionSet GetInstructionSet() const override {
645     return InstructionSet::kArm64;
646   }
647 
648   const Arm64InstructionSetFeatures& GetInstructionSetFeatures() const;
649 
Initialize()650   void Initialize() override {
651     block_labels_.resize(GetGraph()->GetBlocks().size());
652   }
653 
654   // We want to use the STP and LDP instructions to spill and restore registers for slow paths.
655   // These instructions can only encode offsets that are multiples of the register size accessed.
GetPreferredSlotsAlignment()656   uint32_t GetPreferredSlotsAlignment() const override { return vixl::aarch64::kXRegSizeInBytes; }
657 
CreateJumpTable(HPackedSwitch * switch_instr)658   JumpTableARM64* CreateJumpTable(HPackedSwitch* switch_instr) {
659     jump_tables_.emplace_back(new (GetGraph()->GetAllocator()) JumpTableARM64(switch_instr));
660     return jump_tables_.back().get();
661   }
662 
663   void Finalize(CodeAllocator* allocator) override;
664 
665   // Code generation helpers.
666   void MoveConstant(vixl::aarch64::CPURegister destination, HConstant* constant);
667   void MoveConstant(Location destination, int32_t value) override;
668   void MoveLocation(Location dst, Location src, DataType::Type dst_type) override;
669   void AddLocationAsTemp(Location location, LocationSummary* locations) override;
670 
671   void Load(DataType::Type type,
672             vixl::aarch64::CPURegister dst,
673             const vixl::aarch64::MemOperand& src);
674   void Store(DataType::Type type,
675              vixl::aarch64::CPURegister src,
676              const vixl::aarch64::MemOperand& dst);
677   void LoadAcquire(HInstruction* instruction,
678                    DataType::Type type,
679                    vixl::aarch64::CPURegister dst,
680                    const vixl::aarch64::MemOperand& src,
681                    bool needs_null_check);
682   void StoreRelease(HInstruction* instruction,
683                     DataType::Type type,
684                     vixl::aarch64::CPURegister src,
685                     const vixl::aarch64::MemOperand& dst,
686                     bool needs_null_check);
687 
688   // Generate code to invoke a runtime entry point.
689   void InvokeRuntime(QuickEntrypointEnum entrypoint,
690                      HInstruction* instruction,
691                      uint32_t dex_pc,
692                      SlowPathCode* slow_path = nullptr) override;
693 
694   // Generate code to invoke a runtime entry point, but do not record
695   // PC-related information in a stack map.
696   void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
697                                            HInstruction* instruction,
698                                            SlowPathCode* slow_path);
699 
GetMoveResolver()700   ParallelMoveResolverARM64* GetMoveResolver() override { return &move_resolver_; }
701 
NeedsTwoRegisters(DataType::Type type ATTRIBUTE_UNUSED)702   bool NeedsTwoRegisters(DataType::Type type ATTRIBUTE_UNUSED) const override {
703     return false;
704   }
705 
706   // Check if the desired_string_load_kind is supported. If it is, return it,
707   // otherwise return a fall-back kind that should be used instead.
708   HLoadString::LoadKind GetSupportedLoadStringKind(
709       HLoadString::LoadKind desired_string_load_kind) override;
710 
711   // Check if the desired_class_load_kind is supported. If it is, return it,
712   // otherwise return a fall-back kind that should be used instead.
713   HLoadClass::LoadKind GetSupportedLoadClassKind(
714       HLoadClass::LoadKind desired_class_load_kind) override;
715 
716   // Check if the desired_dispatch_info is supported. If it is, return it,
717   // otherwise return a fall-back info that should be used instead.
718   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
719       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
720       ArtMethod* method) override;
721 
722   void LoadMethod(MethodLoadKind load_kind, Location temp, HInvoke* invoke);
723   void GenerateStaticOrDirectCall(
724       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
725   void GenerateVirtualCall(
726       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
727 
728   void MoveFromReturnRegister(Location trg, DataType::Type type) override;
729 
730   // Add a new boot image intrinsic patch for an instruction and return the label
731   // to be bound before the instruction. The instruction will be either the
732   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
733   // to the associated ADRP patch label).
734   vixl::aarch64::Label* NewBootImageIntrinsicPatch(uint32_t intrinsic_data,
735                                                    vixl::aarch64::Label* adrp_label = nullptr);
736 
737   // Add a new boot image relocation patch for an instruction and return the label
738   // to be bound before the instruction. The instruction will be either the
739   // ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` pointing
740   // to the associated ADRP patch label).
741   vixl::aarch64::Label* NewBootImageRelRoPatch(uint32_t boot_image_offset,
742                                                vixl::aarch64::Label* adrp_label = nullptr);
743 
744   // Add a new boot image method patch for an instruction and return the label
745   // to be bound before the instruction. The instruction will be either the
746   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
747   // to the associated ADRP patch label).
748   vixl::aarch64::Label* NewBootImageMethodPatch(MethodReference target_method,
749                                                 vixl::aarch64::Label* adrp_label = nullptr);
750 
751   // Add a new .bss entry method patch for an instruction and return
752   // the label to be bound before the instruction. The instruction will be
753   // either the ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label`
754   // pointing to the associated ADRP patch label).
755   vixl::aarch64::Label* NewMethodBssEntryPatch(MethodReference target_method,
756                                                vixl::aarch64::Label* adrp_label = nullptr);
757 
758   // Add a new boot image type patch for an instruction and return the label
759   // to be bound before the instruction. The instruction will be either the
760   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
761   // to the associated ADRP patch label).
762   vixl::aarch64::Label* NewBootImageTypePatch(const DexFile& dex_file,
763                                               dex::TypeIndex type_index,
764                                               vixl::aarch64::Label* adrp_label = nullptr);
765 
766   // Add a new .bss entry type patch for an instruction and return the label
767   // to be bound before the instruction. The instruction will be either the
768   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
769   // to the associated ADRP patch label).
770   vixl::aarch64::Label* NewBssEntryTypePatch(HLoadClass* load_class,
771                                              vixl::aarch64::Label* adrp_label = nullptr);
772 
773   // Add a new boot image string patch for an instruction and return the label
774   // to be bound before the instruction. The instruction will be either the
775   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
776   // to the associated ADRP patch label).
777   vixl::aarch64::Label* NewBootImageStringPatch(const DexFile& dex_file,
778                                                 dex::StringIndex string_index,
779                                                 vixl::aarch64::Label* adrp_label = nullptr);
780 
781   // Add a new .bss entry string patch for an instruction and return the label
782   // to be bound before the instruction. The instruction will be either the
783   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
784   // to the associated ADRP patch label).
785   vixl::aarch64::Label* NewStringBssEntryPatch(const DexFile& dex_file,
786                                                dex::StringIndex string_index,
787                                                vixl::aarch64::Label* adrp_label = nullptr);
788 
789   // Add a new boot image JNI entrypoint patch for an instruction and return the label
790   // to be bound before the instruction. The instruction will be either the
791   // ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` pointing
792   // to the associated ADRP patch label).
793   vixl::aarch64::Label* NewBootImageJniEntrypointPatch(MethodReference target_method,
794                                                        vixl::aarch64::Label* adrp_label = nullptr);
795 
796   // Emit the BL instruction for entrypoint thunk call and record the associated patch for AOT.
797   void EmitEntrypointThunkCall(ThreadOffset64 entrypoint_offset);
798 
799   // Emit the CBNZ instruction for baker read barrier and record
800   // the associated patch for AOT or slow path for JIT.
801   void EmitBakerReadBarrierCbnz(uint32_t custom_data);
802 
803   vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageAddressLiteral(uint64_t address);
804   vixl::aarch64::Literal<uint32_t>* DeduplicateJitStringLiteral(const DexFile& dex_file,
805                                                                 dex::StringIndex string_index,
806                                                                 Handle<mirror::String> handle);
807   vixl::aarch64::Literal<uint32_t>* DeduplicateJitClassLiteral(const DexFile& dex_file,
808                                                                dex::TypeIndex string_index,
809                                                                Handle<mirror::Class> handle);
810 
811   void EmitAdrpPlaceholder(vixl::aarch64::Label* fixup_label, vixl::aarch64::Register reg);
812   void EmitAddPlaceholder(vixl::aarch64::Label* fixup_label,
813                           vixl::aarch64::Register out,
814                           vixl::aarch64::Register base);
815   void EmitLdrOffsetPlaceholder(vixl::aarch64::Label* fixup_label,
816                                 vixl::aarch64::Register out,
817                                 vixl::aarch64::Register base);
818 
819   void LoadBootImageRelRoEntry(vixl::aarch64::Register reg, uint32_t boot_image_offset);
820   void LoadBootImageAddress(vixl::aarch64::Register reg, uint32_t boot_image_reference);
821   void LoadTypeForBootImageIntrinsic(vixl::aarch64::Register reg, TypeReference type_reference);
822   void LoadIntrinsicDeclaringClass(vixl::aarch64::Register reg, HInvoke* invoke);
823   void LoadClassRootForIntrinsic(vixl::aarch64::Register reg, ClassRoot class_root);
824 
825   void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) override;
826   bool NeedsThunkCode(const linker::LinkerPatch& patch) const override;
827   void EmitThunkCode(const linker::LinkerPatch& patch,
828                      /*out*/ ArenaVector<uint8_t>* code,
829                      /*out*/ std::string* debug_name) override;
830 
831   void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) override;
832 
833   // Generate a GC root reference load:
834   //
835   //   root <- *(obj + offset)
836   //
837   // while honoring read barriers based on read_barrier_option.
838   void GenerateGcRootFieldLoad(HInstruction* instruction,
839                                Location root,
840                                vixl::aarch64::Register obj,
841                                uint32_t offset,
842                                vixl::aarch64::Label* fixup_label,
843                                ReadBarrierOption read_barrier_option);
844   // Generate MOV for the `old_value` in intrinsic CAS and mark it with Baker read barrier.
845   void GenerateIntrinsicCasMoveWithBakerReadBarrier(vixl::aarch64::Register marked_old_value,
846                                                     vixl::aarch64::Register old_value);
847   // Fast path implementation of ReadBarrier::Barrier for a heap
848   // reference field load when Baker's read barriers are used.
849   // Overload suitable for Unsafe.getObject/-Volatile() intrinsic.
850   void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
851                                              Location ref,
852                                              vixl::aarch64::Register obj,
853                                              const vixl::aarch64::MemOperand& src,
854                                              bool needs_null_check,
855                                              bool use_load_acquire);
856   // Fast path implementation of ReadBarrier::Barrier for a heap
857   // reference field load when Baker's read barriers are used.
858   void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
859                                              Location ref,
860                                              vixl::aarch64::Register obj,
861                                              uint32_t offset,
862                                              Location maybe_temp,
863                                              bool needs_null_check,
864                                              bool use_load_acquire);
865   // Fast path implementation of ReadBarrier::Barrier for a heap
866   // reference array load when Baker's read barriers are used.
867   void GenerateArrayLoadWithBakerReadBarrier(HArrayGet* instruction,
868                                              Location ref,
869                                              vixl::aarch64::Register obj,
870                                              uint32_t data_offset,
871                                              Location index,
872                                              bool needs_null_check);
873 
874   // Emit code checking the status of the Marking Register, and
875   // aborting the program if MR does not match the value stored in the
876   // art::Thread object. Code is only emitted in debug mode and if
877   // CompilerOptions::EmitRunTimeChecksInDebugMode returns true.
878   //
879   // Argument `code` is used to identify the different occurrences of
880   // MaybeGenerateMarkingRegisterCheck in the code generator, and is
881   // passed to the BRK instruction.
882   //
883   // If `temp_loc` is a valid location, it is expected to be a
884   // register and will be used as a temporary to generate code;
885   // otherwise, a temporary will be fetched from the core register
886   // scratch pool.
887   virtual void MaybeGenerateMarkingRegisterCheck(int code,
888                                                  Location temp_loc = Location::NoLocation());
889 
890   // Create slow path for a read barrier for a heap reference within `instruction`.
891   //
892   // This is a helper function for GenerateReadBarrierSlow() that has the same
893   // arguments. The creation and adding of the slow path is exposed for intrinsics
894   // that cannot use GenerateReadBarrierSlow() from their own slow paths.
895   SlowPathCodeARM64* AddReadBarrierSlowPath(HInstruction* instruction,
896                                             Location out,
897                                             Location ref,
898                                             Location obj,
899                                             uint32_t offset,
900                                             Location index);
901 
902   // Generate a read barrier for a heap reference within `instruction`
903   // using a slow path.
904   //
905   // A read barrier for an object reference read from the heap is
906   // implemented as a call to the artReadBarrierSlow runtime entry
907   // point, which is passed the values in locations `ref`, `obj`, and
908   // `offset`:
909   //
910   //   mirror::Object* artReadBarrierSlow(mirror::Object* ref,
911   //                                      mirror::Object* obj,
912   //                                      uint32_t offset);
913   //
914   // The `out` location contains the value returned by
915   // artReadBarrierSlow.
916   //
917   // When `index` is provided (i.e. for array accesses), the offset
918   // value passed to artReadBarrierSlow is adjusted to take `index`
919   // into account.
920   void GenerateReadBarrierSlow(HInstruction* instruction,
921                                Location out,
922                                Location ref,
923                                Location obj,
924                                uint32_t offset,
925                                Location index = Location::NoLocation());
926 
927   // If read barriers are enabled, generate a read barrier for a heap
928   // reference using a slow path. If heap poisoning is enabled, also
929   // unpoison the reference in `out`.
930   void MaybeGenerateReadBarrierSlow(HInstruction* instruction,
931                                     Location out,
932                                     Location ref,
933                                     Location obj,
934                                     uint32_t offset,
935                                     Location index = Location::NoLocation());
936 
937   // Generate a read barrier for a GC root within `instruction` using
938   // a slow path.
939   //
940   // A read barrier for an object reference GC root is implemented as
941   // a call to the artReadBarrierForRootSlow runtime entry point,
942   // which is passed the value in location `root`:
943   //
944   //   mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root);
945   //
946   // The `out` location contains the value returned by
947   // artReadBarrierForRootSlow.
948   void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
949 
950   void IncreaseFrame(size_t adjustment) override;
951   void DecreaseFrame(size_t adjustment) override;
952 
953   void GenerateNop() override;
954 
955   void GenerateImplicitNullCheck(HNullCheck* instruction) override;
956   void GenerateExplicitNullCheck(HNullCheck* instruction) override;
957 
MaybeRecordImplicitNullCheck(HInstruction * instr)958   void MaybeRecordImplicitNullCheck(HInstruction* instr) final {
959     // The function must be only called within special scopes
960     // (EmissionCheckScope, ExactAssemblyScope) which prevent generation of
961     // veneer/literal pools by VIXL assembler.
962     CHECK_EQ(GetVIXLAssembler()->ArePoolsBlocked(), true)
963         << "The function must only be called within EmissionCheckScope or ExactAssemblyScope";
964     CodeGenerator::MaybeRecordImplicitNullCheck(instr);
965   }
966 
967   void MaybeGenerateInlineCacheCheck(HInstruction* instruction, vixl::aarch64::Register klass);
968   void MaybeIncrementHotness(bool is_frame_entry);
969 
970   bool CanUseImplicitSuspendCheck() const;
971 
972  private:
973   // Encoding of thunk type and data for link-time generated thunks for Baker read barriers.
974 
975   enum class BakerReadBarrierKind : uint8_t {
976     kField,     // Field get or array get with constant offset (i.e. constant index).
977     kAcquire,   // Volatile field get.
978     kArray,     // Array get with index in register.
979     kGcRoot,    // GC root load.
980     kLast = kGcRoot
981   };
982 
983   static constexpr uint32_t kBakerReadBarrierInvalidEncodedReg = /* sp/zr is invalid */ 31u;
984 
985   static constexpr size_t kBitsForBakerReadBarrierKind =
986       MinimumBitsToStore(static_cast<size_t>(BakerReadBarrierKind::kLast));
987   static constexpr size_t kBakerReadBarrierBitsForRegister =
988       MinimumBitsToStore(kBakerReadBarrierInvalidEncodedReg);
989   using BakerReadBarrierKindField =
990       BitField<BakerReadBarrierKind, 0, kBitsForBakerReadBarrierKind>;
991   using BakerReadBarrierFirstRegField =
992       BitField<uint32_t, kBitsForBakerReadBarrierKind, kBakerReadBarrierBitsForRegister>;
993   using BakerReadBarrierSecondRegField =
994       BitField<uint32_t,
995                kBitsForBakerReadBarrierKind + kBakerReadBarrierBitsForRegister,
996                kBakerReadBarrierBitsForRegister>;
997 
CheckValidReg(uint32_t reg)998   static void CheckValidReg(uint32_t reg) {
999     DCHECK(reg < vixl::aarch64::lr.GetCode() &&
1000            reg != vixl::aarch64::ip0.GetCode() &&
1001            reg != vixl::aarch64::ip1.GetCode()) << reg;
1002   }
1003 
EncodeBakerReadBarrierFieldData(uint32_t base_reg,uint32_t holder_reg)1004   static inline uint32_t EncodeBakerReadBarrierFieldData(uint32_t base_reg, uint32_t holder_reg) {
1005     CheckValidReg(base_reg);
1006     CheckValidReg(holder_reg);
1007     return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kField) |
1008            BakerReadBarrierFirstRegField::Encode(base_reg) |
1009            BakerReadBarrierSecondRegField::Encode(holder_reg);
1010   }
1011 
EncodeBakerReadBarrierAcquireData(uint32_t base_reg,uint32_t holder_reg)1012   static inline uint32_t EncodeBakerReadBarrierAcquireData(uint32_t base_reg, uint32_t holder_reg) {
1013     CheckValidReg(base_reg);
1014     CheckValidReg(holder_reg);
1015     DCHECK_NE(base_reg, holder_reg);
1016     return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kAcquire) |
1017            BakerReadBarrierFirstRegField::Encode(base_reg) |
1018            BakerReadBarrierSecondRegField::Encode(holder_reg);
1019   }
1020 
EncodeBakerReadBarrierArrayData(uint32_t base_reg)1021   static inline uint32_t EncodeBakerReadBarrierArrayData(uint32_t base_reg) {
1022     CheckValidReg(base_reg);
1023     return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kArray) |
1024            BakerReadBarrierFirstRegField::Encode(base_reg) |
1025            BakerReadBarrierSecondRegField::Encode(kBakerReadBarrierInvalidEncodedReg);
1026   }
1027 
EncodeBakerReadBarrierGcRootData(uint32_t root_reg)1028   static inline uint32_t EncodeBakerReadBarrierGcRootData(uint32_t root_reg) {
1029     CheckValidReg(root_reg);
1030     return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kGcRoot) |
1031            BakerReadBarrierFirstRegField::Encode(root_reg) |
1032            BakerReadBarrierSecondRegField::Encode(kBakerReadBarrierInvalidEncodedReg);
1033   }
1034 
1035   void CompileBakerReadBarrierThunk(Arm64Assembler& assembler,
1036                                     uint32_t encoded_data,
1037                                     /*out*/ std::string* debug_name);
1038 
1039   using Uint64ToLiteralMap = ArenaSafeMap<uint64_t, vixl::aarch64::Literal<uint64_t>*>;
1040   using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, vixl::aarch64::Literal<uint32_t>*>;
1041   using StringToLiteralMap = ArenaSafeMap<StringReference,
1042                                           vixl::aarch64::Literal<uint32_t>*,
1043                                           StringReferenceValueComparator>;
1044   using TypeToLiteralMap = ArenaSafeMap<TypeReference,
1045                                         vixl::aarch64::Literal<uint32_t>*,
1046                                         TypeReferenceValueComparator>;
1047 
1048   vixl::aarch64::Literal<uint32_t>* DeduplicateUint32Literal(uint32_t value);
1049   vixl::aarch64::Literal<uint64_t>* DeduplicateUint64Literal(uint64_t value);
1050 
1051   // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types,
1052   // whether through .data.bimg.rel.ro, .bss, or directly in the boot image.
1053   struct PcRelativePatchInfo : PatchInfo<vixl::aarch64::Label> {
PcRelativePatchInfoPcRelativePatchInfo1054     PcRelativePatchInfo(const DexFile* dex_file, uint32_t off_or_idx)
1055         : PatchInfo<vixl::aarch64::Label>(dex_file, off_or_idx), pc_insn_label() { }
1056 
1057     vixl::aarch64::Label* pc_insn_label;
1058   };
1059 
1060   struct BakerReadBarrierPatchInfo {
BakerReadBarrierPatchInfoBakerReadBarrierPatchInfo1061     explicit BakerReadBarrierPatchInfo(uint32_t data) : label(), custom_data(data) { }
1062 
1063     vixl::aarch64::Label label;
1064     uint32_t custom_data;
1065   };
1066 
1067   vixl::aarch64::Label* NewPcRelativePatch(const DexFile* dex_file,
1068                                            uint32_t offset_or_index,
1069                                            vixl::aarch64::Label* adrp_label,
1070                                            ArenaDeque<PcRelativePatchInfo>* patches);
1071 
1072   void EmitJumpTables();
1073 
1074   template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
1075   static void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
1076                                           ArenaVector<linker::LinkerPatch>* linker_patches);
1077 
1078   // Returns whether SVE features are supported and should be used.
1079   bool ShouldUseSVE() const;
1080 
1081   // Labels for each block that will be compiled.
1082   // We use a deque so that the `vixl::aarch64::Label` objects do not move in memory.
1083   ArenaDeque<vixl::aarch64::Label> block_labels_;  // Indexed by block id.
1084   vixl::aarch64::Label frame_entry_label_;
1085   ArenaVector<std::unique_ptr<JumpTableARM64>> jump_tables_;
1086 
1087   LocationsBuilderARM64Neon location_builder_neon_;
1088   InstructionCodeGeneratorARM64Neon instruction_visitor_neon_;
1089   LocationsBuilderARM64Sve location_builder_sve_;
1090   InstructionCodeGeneratorARM64Sve instruction_visitor_sve_;
1091 
1092   LocationsBuilderARM64* location_builder_;
1093   InstructionCodeGeneratorARM64* instruction_visitor_;
1094   ParallelMoveResolverARM64 move_resolver_;
1095   Arm64Assembler assembler_;
1096 
1097   // PC-relative method patch info for kBootImageLinkTimePcRelative.
1098   ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
1099   // PC-relative method patch info for kBssEntry.
1100   ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
1101   // PC-relative type patch info for kBootImageLinkTimePcRelative.
1102   ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_;
1103   // PC-relative type patch info for kBssEntry.
1104   ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
1105   // PC-relative public type patch info for kBssEntryPublic.
1106   ArenaDeque<PcRelativePatchInfo> public_type_bss_entry_patches_;
1107   // PC-relative package type patch info for kBssEntryPackage.
1108   ArenaDeque<PcRelativePatchInfo> package_type_bss_entry_patches_;
1109   // PC-relative String patch info for kBootImageLinkTimePcRelative.
1110   ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_;
1111   // PC-relative String patch info for kBssEntry.
1112   ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_;
1113   // PC-relative method patch info for kBootImageLinkTimePcRelative+kCallCriticalNative.
1114   ArenaDeque<PcRelativePatchInfo> boot_image_jni_entrypoint_patches_;
1115   // PC-relative patch info for IntrinsicObjects for the boot image,
1116   // and for method/type/string patches for kBootImageRelRo otherwise.
1117   ArenaDeque<PcRelativePatchInfo> boot_image_other_patches_;
1118   // Patch info for calls to entrypoint dispatch thunks. Used for slow paths.
1119   ArenaDeque<PatchInfo<vixl::aarch64::Label>> call_entrypoint_patches_;
1120   // Baker read barrier patch info.
1121   ArenaDeque<BakerReadBarrierPatchInfo> baker_read_barrier_patches_;
1122 
1123   // Deduplication map for 32-bit literals, used for JIT for boot image addresses.
1124   Uint32ToLiteralMap uint32_literals_;
1125   // Deduplication map for 64-bit literals, used for JIT for method address or method code.
1126   Uint64ToLiteralMap uint64_literals_;
1127   // Patches for string literals in JIT compiled code.
1128   StringToLiteralMap jit_string_patches_;
1129   // Patches for class literals in JIT compiled code.
1130   TypeToLiteralMap jit_class_patches_;
1131 
1132   // Baker read barrier slow paths, mapping custom data (uint32_t) to label.
1133   // Wrap the label to work around vixl::aarch64::Label being non-copyable
1134   // and non-moveable and as such unusable in ArenaSafeMap<>.
1135   struct LabelWrapper {
LabelWrapperLabelWrapper1136     LabelWrapper(const LabelWrapper& src)
1137         : label() {
1138       DCHECK(!src.label.IsLinked() && !src.label.IsBound());
1139     }
1140     LabelWrapper() = default;
1141     vixl::aarch64::Label label;
1142   };
1143   ArenaSafeMap<uint32_t, LabelWrapper> jit_baker_read_barrier_slow_paths_;
1144 
1145   friend class linker::Arm64RelativePatcherTest;
1146   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM64);
1147 };
1148 
GetAssembler()1149 inline Arm64Assembler* ParallelMoveResolverARM64::GetAssembler() const {
1150   return codegen_->GetAssembler();
1151 }
1152 
1153 }  // namespace arm64
1154 }  // namespace art
1155 
1156 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM64_H_
1157