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 "code_generator.h"
21 #include "dex/compiler_enums.h"
22 #include "driver/compiler_options.h"
23 #include "nodes.h"
24 #include "parallel_move_resolver.h"
25 #include "utils/arm64/assembler_arm64.h"
26 #include "vixl/a64/disasm-a64.h"
27 #include "vixl/a64/macro-assembler-a64.h"
28 #include "arch/arm64/quick_method_frame_info_arm64.h"
29 
30 namespace art {
31 namespace arm64 {
32 
33 class CodeGeneratorARM64;
34 
35 // Use a local definition to prevent copying mistakes.
36 static constexpr size_t kArm64WordSize = kArm64PointerSize;
37 
38 static const vixl::Register kParameterCoreRegisters[] = {
39   vixl::x1, vixl::x2, vixl::x3, vixl::x4, vixl::x5, vixl::x6, vixl::x7
40 };
41 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
42 static const vixl::FPRegister kParameterFPRegisters[] = {
43   vixl::d0, vixl::d1, vixl::d2, vixl::d3, vixl::d4, vixl::d5, vixl::d6, vixl::d7
44 };
45 static constexpr size_t kParameterFPRegistersLength = arraysize(kParameterFPRegisters);
46 
47 const vixl::Register tr = vixl::x18;                        // Thread Register
48 static const vixl::Register kArtMethodRegister = vixl::x0;  // Method register on invoke.
49 
50 const vixl::CPURegList vixl_reserved_core_registers(vixl::ip0, vixl::ip1);
51 const vixl::CPURegList vixl_reserved_fp_registers(vixl::d31);
52 
53 const vixl::CPURegList runtime_reserved_core_registers(tr, vixl::lr);
54 
55 // Callee-saved registers defined by AAPCS64.
56 const vixl::CPURegList callee_saved_core_registers(vixl::CPURegister::kRegister,
57                                                    vixl::kXRegSize,
58                                                    vixl::x19.code(),
59                                                    vixl::x30.code());
60 const vixl::CPURegList callee_saved_fp_registers(vixl::CPURegister::kFPRegister,
61                                                  vixl::kDRegSize,
62                                                  vixl::d8.code(),
63                                                  vixl::d15.code());
64 Location ARM64ReturnLocation(Primitive::Type return_type);
65 
66 class SlowPathCodeARM64 : public SlowPathCode {
67  public:
SlowPathCodeARM64()68   SlowPathCodeARM64() : entry_label_(), exit_label_() {}
69 
GetEntryLabel()70   vixl::Label* GetEntryLabel() { return &entry_label_; }
GetExitLabel()71   vixl::Label* GetExitLabel() { return &exit_label_; }
72 
73  private:
74   vixl::Label entry_label_;
75   vixl::Label exit_label_;
76 
77   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM64);
78 };
79 
80 static const vixl::Register kRuntimeParameterCoreRegisters[] =
81     { vixl::x0, vixl::x1, vixl::x2, vixl::x3, vixl::x4, vixl::x5, vixl::x6, vixl::x7 };
82 static constexpr size_t kRuntimeParameterCoreRegistersLength =
83     arraysize(kRuntimeParameterCoreRegisters);
84 static const vixl::FPRegister kRuntimeParameterFpuRegisters[] =
85     { vixl::d0, vixl::d1, vixl::d2, vixl::d3, vixl::d4, vixl::d5, vixl::d6, vixl::d7 };
86 static constexpr size_t kRuntimeParameterFpuRegistersLength =
87     arraysize(kRuntimeParameterCoreRegisters);
88 
89 class InvokeRuntimeCallingConvention : public CallingConvention<vixl::Register, vixl::FPRegister> {
90  public:
91   static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
92 
InvokeRuntimeCallingConvention()93   InvokeRuntimeCallingConvention()
94       : CallingConvention(kRuntimeParameterCoreRegisters,
95                           kRuntimeParameterCoreRegistersLength,
96                           kRuntimeParameterFpuRegisters,
97                           kRuntimeParameterFpuRegistersLength,
98                           kArm64PointerSize) {}
99 
100   Location GetReturnLocation(Primitive::Type return_type);
101 
102  private:
103   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
104 };
105 
106 class InvokeDexCallingConvention : public CallingConvention<vixl::Register, vixl::FPRegister> {
107  public:
InvokeDexCallingConvention()108   InvokeDexCallingConvention()
109       : CallingConvention(kParameterCoreRegisters,
110                           kParameterCoreRegistersLength,
111                           kParameterFPRegisters,
112                           kParameterFPRegistersLength,
113                           kArm64PointerSize) {}
114 
GetReturnLocation(Primitive::Type return_type)115   Location GetReturnLocation(Primitive::Type return_type) {
116     return ARM64ReturnLocation(return_type);
117   }
118 
119 
120  private:
121   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
122 };
123 
124 class InvokeDexCallingConventionVisitorARM64 : public InvokeDexCallingConventionVisitor {
125  public:
InvokeDexCallingConventionVisitorARM64()126   InvokeDexCallingConventionVisitorARM64() {}
~InvokeDexCallingConventionVisitorARM64()127   virtual ~InvokeDexCallingConventionVisitorARM64() {}
128 
129   Location GetNextLocation(Primitive::Type type) OVERRIDE;
GetReturnLocation(Primitive::Type return_type)130   Location GetReturnLocation(Primitive::Type return_type) {
131     return calling_convention.GetReturnLocation(return_type);
132   }
133 
134  private:
135   InvokeDexCallingConvention calling_convention;
136 
137   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorARM64);
138 };
139 
140 class InstructionCodeGeneratorARM64 : public HGraphVisitor {
141  public:
142   InstructionCodeGeneratorARM64(HGraph* graph, CodeGeneratorARM64* codegen);
143 
144 #define DECLARE_VISIT_INSTRUCTION(name, super) \
145   void Visit##name(H##name* instr) OVERRIDE;
146   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
147 #undef DECLARE_VISIT_INSTRUCTION
148 
149   void LoadCurrentMethod(XRegister reg);
150 
GetAssembler()151   Arm64Assembler* GetAssembler() const { return assembler_; }
GetVIXLAssembler()152   vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
153 
154  private:
155   void GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path, vixl::Register class_reg);
156   void GenerateMemoryBarrier(MemBarrierKind kind);
157   void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
158   void HandleBinaryOp(HBinaryOperation* instr);
159   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
160   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
161   void HandleShift(HBinaryOperation* instr);
162   void GenerateImplicitNullCheck(HNullCheck* instruction);
163   void GenerateExplicitNullCheck(HNullCheck* instruction);
164   void GenerateTestAndBranch(HInstruction* instruction,
165                              vixl::Label* true_target,
166                              vixl::Label* false_target,
167                              vixl::Label* always_true_target);
168 
169   Arm64Assembler* const assembler_;
170   CodeGeneratorARM64* const codegen_;
171 
172   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorARM64);
173 };
174 
175 class LocationsBuilderARM64 : public HGraphVisitor {
176  public:
LocationsBuilderARM64(HGraph * graph,CodeGeneratorARM64 * codegen)177   explicit LocationsBuilderARM64(HGraph* graph, CodeGeneratorARM64* codegen)
178       : HGraphVisitor(graph), codegen_(codegen) {}
179 
180 #define DECLARE_VISIT_INSTRUCTION(name, super) \
181   void Visit##name(H##name* instr) OVERRIDE;
182   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
183 #undef DECLARE_VISIT_INSTRUCTION
184 
185  private:
186   void HandleBinaryOp(HBinaryOperation* instr);
187   void HandleFieldSet(HInstruction* instruction);
188   void HandleFieldGet(HInstruction* instruction);
189   void HandleInvoke(HInvoke* instr);
190   void HandleShift(HBinaryOperation* instr);
191 
192   CodeGeneratorARM64* const codegen_;
193   InvokeDexCallingConventionVisitorARM64 parameter_visitor_;
194 
195   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM64);
196 };
197 
198 class ParallelMoveResolverARM64 : public ParallelMoveResolverNoSwap {
199  public:
ParallelMoveResolverARM64(ArenaAllocator * allocator,CodeGeneratorARM64 * codegen)200   ParallelMoveResolverARM64(ArenaAllocator* allocator, CodeGeneratorARM64* codegen)
201       : ParallelMoveResolverNoSwap(allocator), codegen_(codegen), vixl_temps_() {}
202 
203  protected:
204   void PrepareForEmitNativeCode() OVERRIDE;
205   void FinishEmitNativeCode() OVERRIDE;
206   Location AllocateScratchLocationFor(Location::Kind kind) OVERRIDE;
207   void FreeScratchLocation(Location loc) OVERRIDE;
208   void EmitMove(size_t index) OVERRIDE;
209 
210  private:
211   Arm64Assembler* GetAssembler() const;
GetVIXLAssembler()212   vixl::MacroAssembler* GetVIXLAssembler() const {
213     return GetAssembler()->vixl_masm_;
214   }
215 
216   CodeGeneratorARM64* const codegen_;
217   vixl::UseScratchRegisterScope vixl_temps_;
218 
219   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverARM64);
220 };
221 
222 class CodeGeneratorARM64 : public CodeGenerator {
223  public:
224   CodeGeneratorARM64(HGraph* graph,
225                      const Arm64InstructionSetFeatures& isa_features,
226                      const CompilerOptions& compiler_options);
~CodeGeneratorARM64()227   virtual ~CodeGeneratorARM64() {}
228 
229   void GenerateFrameEntry() OVERRIDE;
230   void GenerateFrameExit() OVERRIDE;
231 
GetFramePreservedCoreRegisters()232   vixl::CPURegList GetFramePreservedCoreRegisters() const {
233     return vixl::CPURegList(vixl::CPURegister::kRegister, vixl::kXRegSize,
234                             core_spill_mask_);
235   }
236 
GetFramePreservedFPRegisters()237   vixl::CPURegList GetFramePreservedFPRegisters() const {
238     return vixl::CPURegList(vixl::CPURegister::kFPRegister, vixl::kDRegSize,
239                             fpu_spill_mask_);
240   }
241 
242   void Bind(HBasicBlock* block) OVERRIDE;
243 
GetLabelOf(HBasicBlock * block)244   vixl::Label* GetLabelOf(HBasicBlock* block) const {
245     return CommonGetLabelOf<vixl::Label>(block_labels_, block);
246   }
247 
248   void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
249 
GetWordSize()250   size_t GetWordSize() const OVERRIDE {
251     return kArm64WordSize;
252   }
253 
GetFloatingPointSpillSlotSize()254   size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
255     // Allocated in D registers, which are word sized.
256     return kArm64WordSize;
257   }
258 
GetAddressOf(HBasicBlock * block)259   uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
260     vixl::Label* block_entry_label = GetLabelOf(block);
261     DCHECK(block_entry_label->IsBound());
262     return block_entry_label->location();
263   }
264 
GetLocationBuilder()265   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
GetInstructionVisitor()266   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
GetAssembler()267   Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
GetVIXLAssembler()268   vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
269 
270   // Emit a write barrier.
271   void MarkGCCard(vixl::Register object, vixl::Register value);
272 
273   // Register allocation.
274 
275   void SetupBlockedRegisters(bool is_baseline) const OVERRIDE;
276   // AllocateFreeRegister() is only used when allocating registers locally
277   // during CompileBaseline().
278   Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
279 
280   Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
281 
282   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
283   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
284   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
285   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
286 
287   // The number of registers that can be allocated. The register allocator may
288   // decide to reserve and not use a few of them.
289   // We do not consider registers sp, xzr, wzr. They are either not allocatable
290   // (xzr, wzr), or make for poor allocatable registers (sp alignment
291   // requirements, etc.). This also facilitates our task as all other registers
292   // can easily be mapped via to or from their type and index or code.
293   static const int kNumberOfAllocatableRegisters = vixl::kNumberOfRegisters - 1;
294   static const int kNumberOfAllocatableFPRegisters = vixl::kNumberOfFPRegisters;
295   static constexpr int kNumberOfAllocatableRegisterPairs = 0;
296 
297   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
298   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
299 
GetInstructionSet()300   InstructionSet GetInstructionSet() const OVERRIDE {
301     return InstructionSet::kArm64;
302   }
303 
GetInstructionSetFeatures()304   const Arm64InstructionSetFeatures& GetInstructionSetFeatures() const {
305     return isa_features_;
306   }
307 
Initialize()308   void Initialize() OVERRIDE {
309     HGraph* graph = GetGraph();
310     int length = graph->GetBlocks().Size();
311     block_labels_ = graph->GetArena()->AllocArray<vixl::Label>(length);
312     for (int i = 0; i < length; ++i) {
313       new(block_labels_ + i) vixl::Label();
314     }
315   }
316 
317   void Finalize(CodeAllocator* allocator) OVERRIDE;
318 
319   // Code generation helpers.
320   void MoveConstant(vixl::CPURegister destination, HConstant* constant);
321   // The type is optional. When specified it must be coherent with the
322   // locations, and is used for optimisation and debugging.
323   void MoveLocation(Location destination, Location source,
324                     Primitive::Type type = Primitive::kPrimVoid);
325   void Load(Primitive::Type type, vixl::CPURegister dst, const vixl::MemOperand& src);
326   void Store(Primitive::Type type, vixl::CPURegister rt, const vixl::MemOperand& dst);
327   void LoadCurrentMethod(vixl::Register current_method);
328   void LoadAcquire(HInstruction* instruction, vixl::CPURegister dst, const vixl::MemOperand& src);
329   void StoreRelease(Primitive::Type type, vixl::CPURegister rt, const vixl::MemOperand& dst);
330 
331   // Generate code to invoke a runtime entry point.
332   void InvokeRuntime(int32_t offset,
333                      HInstruction* instruction,
334                      uint32_t dex_pc,
335                      SlowPathCode* slow_path);
336 
GetMoveResolver()337   ParallelMoveResolverARM64* GetMoveResolver() { return &move_resolver_; }
338 
NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED)339   bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
340     return false;
341   }
342 
343   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, vixl::Register temp);
344 
345  private:
346   // Labels for each block that will be compiled.
347   vixl::Label* block_labels_;
348   vixl::Label frame_entry_label_;
349 
350   LocationsBuilderARM64 location_builder_;
351   InstructionCodeGeneratorARM64 instruction_visitor_;
352   ParallelMoveResolverARM64 move_resolver_;
353   Arm64Assembler assembler_;
354   const Arm64InstructionSetFeatures& isa_features_;
355 
356   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM64);
357 };
358 
GetAssembler()359 inline Arm64Assembler* ParallelMoveResolverARM64::GetAssembler() const {
360   return codegen_->GetAssembler();
361 }
362 
363 }  // namespace arm64
364 }  // namespace art
365 
366 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM64_H_
367