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_X86_64_H_
18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_64_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/x86_64/assembler_x86_64.h"
26 
27 namespace art {
28 namespace x86_64 {
29 
30 // Use a local definition to prevent copying mistakes.
31 static constexpr size_t kX86_64WordSize = kX86_64PointerSize;
32 
33 static constexpr Register kParameterCoreRegisters[] = { RSI, RDX, RCX, R8, R9 };
34 static constexpr FloatRegister kParameterFloatRegisters[] =
35     { XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7 };
36 
37 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
38 static constexpr size_t kParameterFloatRegistersLength = arraysize(kParameterFloatRegisters);
39 
40 static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX, RCX };
41 static constexpr size_t kRuntimeParameterCoreRegistersLength =
42     arraysize(kRuntimeParameterCoreRegisters);
43 static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1 };
44 static constexpr size_t kRuntimeParameterFpuRegistersLength =
45     arraysize(kRuntimeParameterFpuRegisters);
46 
47 class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> {
48  public:
InvokeRuntimeCallingConvention()49   InvokeRuntimeCallingConvention()
50       : CallingConvention(kRuntimeParameterCoreRegisters,
51                           kRuntimeParameterCoreRegistersLength,
52                           kRuntimeParameterFpuRegisters,
53                           kRuntimeParameterFpuRegistersLength,
54                           kX86_64PointerSize) {}
55 
56  private:
57   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
58 };
59 
60 class InvokeDexCallingConvention : public CallingConvention<Register, FloatRegister> {
61  public:
InvokeDexCallingConvention()62   InvokeDexCallingConvention() : CallingConvention(
63       kParameterCoreRegisters,
64       kParameterCoreRegistersLength,
65       kParameterFloatRegisters,
66       kParameterFloatRegistersLength,
67       kX86_64PointerSize) {}
68 
69  private:
70   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
71 };
72 
73 class InvokeDexCallingConventionVisitorX86_64 : public InvokeDexCallingConventionVisitor {
74  public:
InvokeDexCallingConventionVisitorX86_64()75   InvokeDexCallingConventionVisitorX86_64() {}
~InvokeDexCallingConventionVisitorX86_64()76   virtual ~InvokeDexCallingConventionVisitorX86_64() {}
77 
78   Location GetNextLocation(Primitive::Type type) OVERRIDE;
79 
80  private:
81   InvokeDexCallingConvention calling_convention;
82 
83   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorX86_64);
84 };
85 
86 class CodeGeneratorX86_64;
87 
88 class SlowPathCodeX86_64 : public SlowPathCode {
89  public:
SlowPathCodeX86_64()90   SlowPathCodeX86_64() : entry_label_(), exit_label_() {}
91 
GetEntryLabel()92   Label* GetEntryLabel() { return &entry_label_; }
GetExitLabel()93   Label* GetExitLabel() { return &exit_label_; }
94 
95  private:
96   Label entry_label_;
97   Label exit_label_;
98 
99   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeX86_64);
100 };
101 
102 class ParallelMoveResolverX86_64 : public ParallelMoveResolverWithSwap {
103  public:
ParallelMoveResolverX86_64(ArenaAllocator * allocator,CodeGeneratorX86_64 * codegen)104   ParallelMoveResolverX86_64(ArenaAllocator* allocator, CodeGeneratorX86_64* codegen)
105       : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
106 
107   void EmitMove(size_t index) OVERRIDE;
108   void EmitSwap(size_t index) OVERRIDE;
109   void SpillScratch(int reg) OVERRIDE;
110   void RestoreScratch(int reg) OVERRIDE;
111 
112   X86_64Assembler* GetAssembler() const;
113 
114  private:
115   void Exchange32(CpuRegister reg, int mem);
116   void Exchange32(XmmRegister reg, int mem);
117   void Exchange32(int mem1, int mem2);
118   void Exchange64(CpuRegister reg, int mem);
119   void Exchange64(XmmRegister reg, int mem);
120   void Exchange64(int mem1, int mem2);
121 
122   CodeGeneratorX86_64* const codegen_;
123 
124   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverX86_64);
125 };
126 
127 class LocationsBuilderX86_64 : public HGraphVisitor {
128  public:
LocationsBuilderX86_64(HGraph * graph,CodeGeneratorX86_64 * codegen)129   LocationsBuilderX86_64(HGraph* graph, CodeGeneratorX86_64* codegen)
130       : HGraphVisitor(graph), codegen_(codegen) {}
131 
132 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
133   void Visit##name(H##name* instr) OVERRIDE;
134 
135   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
136 
137 #undef DECLARE_VISIT_INSTRUCTION
138 
139  private:
140   void HandleInvoke(HInvoke* invoke);
141   void HandleBitwiseOperation(HBinaryOperation* operation);
142   void HandleShift(HBinaryOperation* operation);
143   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
144   void HandleFieldGet(HInstruction* instruction);
145 
146   CodeGeneratorX86_64* const codegen_;
147   InvokeDexCallingConventionVisitorX86_64 parameter_visitor_;
148 
149   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86_64);
150 };
151 
152 class InstructionCodeGeneratorX86_64 : public HGraphVisitor {
153  public:
154   InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen);
155 
156 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
157   void Visit##name(H##name* instr) OVERRIDE;
158 
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)159   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
160 
161 #undef DECLARE_VISIT_INSTRUCTION
162 
163   X86_64Assembler* GetAssembler() const { return assembler_; }
164 
165  private:
166   // Generate code for the given suspend check. If not null, `successor`
167   // is the block to branch to if the suspend check is not needed, and after
168   // the suspend call.
169   void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
170   void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg);
171   void HandleBitwiseOperation(HBinaryOperation* operation);
172   void GenerateRemFP(HRem *rem);
173   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
174   void DivByPowerOfTwo(HDiv* instruction);
175   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
176   void GenerateDivRemIntegral(HBinaryOperation* instruction);
177   void HandleShift(HBinaryOperation* operation);
178   void GenerateMemoryBarrier(MemBarrierKind kind);
179   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
180   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
181   void GenerateImplicitNullCheck(HNullCheck* instruction);
182   void GenerateExplicitNullCheck(HNullCheck* instruction);
183   void PushOntoFPStack(Location source, uint32_t temp_offset,
184                        uint32_t stack_adjustment, bool is_float);
185   void GenerateTestAndBranch(HInstruction* instruction,
186                              Label* true_target,
187                              Label* false_target,
188                              Label* always_true_target);
189 
190   X86_64Assembler* const assembler_;
191   CodeGeneratorX86_64* const codegen_;
192 
193   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86_64);
194 };
195 
196 class CodeGeneratorX86_64 : public CodeGenerator {
197  public:
198   CodeGeneratorX86_64(HGraph* graph,
199                   const X86_64InstructionSetFeatures& isa_features,
200                   const CompilerOptions& compiler_options);
~CodeGeneratorX86_64()201   virtual ~CodeGeneratorX86_64() {}
202 
203   void GenerateFrameEntry() OVERRIDE;
204   void GenerateFrameExit() OVERRIDE;
205   void Bind(HBasicBlock* block) OVERRIDE;
206   void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
207   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
208   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
209   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
210   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
211 
GetWordSize()212   size_t GetWordSize() const OVERRIDE {
213     return kX86_64WordSize;
214   }
215 
GetFloatingPointSpillSlotSize()216   size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
217     return kX86_64WordSize;
218   }
219 
GetLocationBuilder()220   HGraphVisitor* GetLocationBuilder() OVERRIDE {
221     return &location_builder_;
222   }
223 
GetInstructionVisitor()224   HGraphVisitor* GetInstructionVisitor() OVERRIDE {
225     return &instruction_visitor_;
226   }
227 
GetAssembler()228   X86_64Assembler* GetAssembler() OVERRIDE {
229     return &assembler_;
230   }
231 
GetMoveResolver()232   ParallelMoveResolverX86_64* GetMoveResolver() OVERRIDE {
233     return &move_resolver_;
234   }
235 
GetAddressOf(HBasicBlock * block)236   uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
237     return GetLabelOf(block)->Position();
238   }
239 
240   Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
241 
242   void SetupBlockedRegisters(bool is_baseline) const OVERRIDE;
243   Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
244   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
245   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
246   void Finalize(CodeAllocator* allocator) OVERRIDE;
247 
GetInstructionSet()248   InstructionSet GetInstructionSet() const OVERRIDE {
249     return InstructionSet::kX86_64;
250   }
251 
252   // Emit a write barrier.
253   void MarkGCCard(CpuRegister temp, CpuRegister card, CpuRegister object, CpuRegister value);
254 
255   // Helper method to move a value between two locations.
256   void Move(Location destination, Location source);
257 
258   void LoadCurrentMethod(CpuRegister reg);
259 
GetLabelOf(HBasicBlock * block)260   Label* GetLabelOf(HBasicBlock* block) const {
261     return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
262   }
263 
Initialize()264   void Initialize() OVERRIDE {
265     block_labels_.SetSize(GetGraph()->GetBlocks().Size());
266   }
267 
NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED)268   bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
269     return false;
270   }
271 
272   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, CpuRegister temp);
273 
GetInstructionSetFeatures()274   const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const {
275     return isa_features_;
276   }
277 
ConstantAreaStart()278   int ConstantAreaStart() const {
279     return constant_area_start_;
280   }
281 
282   Address LiteralDoubleAddress(double v);
283   Address LiteralFloatAddress(float v);
284   Address LiteralInt32Address(int32_t v);
285   Address LiteralInt64Address(int64_t v);
286 
287   // Load a 64 bit value into a register in the most efficient manner.
288   void Load64BitValue(CpuRegister dest, int64_t value);
289 
290  private:
291   // Labels for each block that will be compiled.
292   GrowableArray<Label> block_labels_;
293   Label frame_entry_label_;
294   LocationsBuilderX86_64 location_builder_;
295   InstructionCodeGeneratorX86_64 instruction_visitor_;
296   ParallelMoveResolverX86_64 move_resolver_;
297   X86_64Assembler assembler_;
298   const X86_64InstructionSetFeatures& isa_features_;
299 
300   // Offset to the start of the constant area in the assembled code.
301   // Used for fixups to the constant area.
302   int constant_area_start_;
303 
304   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86_64);
305 };
306 
307 }  // namespace x86_64
308 }  // namespace art
309 
310 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_64_H_
311