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_H_
18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_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/assembler_x86.h"
26 
27 namespace art {
28 namespace x86 {
29 
30 // Use a local definition to prevent copying mistakes.
31 static constexpr size_t kX86WordSize = kX86PointerSize;
32 
33 class CodeGeneratorX86;
34 class SlowPathCodeX86;
35 
36 static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX };
37 static constexpr RegisterPair kParameterCorePairRegisters[] = { ECX_EDX, EDX_EBX };
38 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
39 static constexpr XmmRegister kParameterFpuRegisters[] = { XMM0, XMM1, XMM2, XMM3 };
40 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
41 
42 static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX, EBX };
43 static constexpr size_t kRuntimeParameterCoreRegistersLength =
44     arraysize(kRuntimeParameterCoreRegisters);
45 static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1, XMM2, XMM3 };
46 static constexpr size_t kRuntimeParameterFpuRegistersLength =
47     arraysize(kRuntimeParameterFpuRegisters);
48 
49 class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> {
50  public:
InvokeRuntimeCallingConvention()51   InvokeRuntimeCallingConvention()
52       : CallingConvention(kRuntimeParameterCoreRegisters,
53                           kRuntimeParameterCoreRegistersLength,
54                           kRuntimeParameterFpuRegisters,
55                           kRuntimeParameterFpuRegistersLength,
56                           kX86PointerSize) {}
57 
58  private:
59   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
60 };
61 
62 class InvokeDexCallingConvention : public CallingConvention<Register, XmmRegister> {
63  public:
InvokeDexCallingConvention()64   InvokeDexCallingConvention() : CallingConvention(
65       kParameterCoreRegisters,
66       kParameterCoreRegistersLength,
67       kParameterFpuRegisters,
68       kParameterFpuRegistersLength,
69       kX86PointerSize) {}
70 
GetRegisterPairAt(size_t argument_index)71   RegisterPair GetRegisterPairAt(size_t argument_index) {
72     DCHECK_LT(argument_index + 1, GetNumberOfRegisters());
73     return kParameterCorePairRegisters[argument_index];
74   }
75 
76  private:
77   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
78 };
79 
80 class InvokeDexCallingConventionVisitorX86 : public InvokeDexCallingConventionVisitor {
81  public:
InvokeDexCallingConventionVisitorX86()82   InvokeDexCallingConventionVisitorX86() {}
~InvokeDexCallingConventionVisitorX86()83   virtual ~InvokeDexCallingConventionVisitorX86() {}
84 
85   Location GetNextLocation(Primitive::Type type) OVERRIDE;
86 
87  private:
88   InvokeDexCallingConvention calling_convention;
89 
90   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorX86);
91 };
92 
93 class ParallelMoveResolverX86 : public ParallelMoveResolverWithSwap {
94  public:
ParallelMoveResolverX86(ArenaAllocator * allocator,CodeGeneratorX86 * codegen)95   ParallelMoveResolverX86(ArenaAllocator* allocator, CodeGeneratorX86* codegen)
96       : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
97 
98   void EmitMove(size_t index) OVERRIDE;
99   void EmitSwap(size_t index) OVERRIDE;
100   void SpillScratch(int reg) OVERRIDE;
101   void RestoreScratch(int reg) OVERRIDE;
102 
103   X86Assembler* GetAssembler() const;
104 
105  private:
106   void Exchange(Register reg, int mem);
107   void Exchange(int mem1, int mem2);
108   void Exchange32(XmmRegister reg, int mem);
109   void MoveMemoryToMemory32(int dst, int src);
110   void MoveMemoryToMemory64(int dst, int src);
111 
112   CodeGeneratorX86* const codegen_;
113 
114   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverX86);
115 };
116 
117 class LocationsBuilderX86 : public HGraphVisitor {
118  public:
LocationsBuilderX86(HGraph * graph,CodeGeneratorX86 * codegen)119   LocationsBuilderX86(HGraph* graph, CodeGeneratorX86* codegen)
120       : HGraphVisitor(graph), codegen_(codegen) {}
121 
122 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
123   void Visit##name(H##name* instr) OVERRIDE;
124 
125   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
126 
127 #undef DECLARE_VISIT_INSTRUCTION
128 
129  private:
130   void HandleBitwiseOperation(HBinaryOperation* instruction);
131   void HandleInvoke(HInvoke* invoke);
132   void HandleShift(HBinaryOperation* instruction);
133   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
134   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
135 
136   CodeGeneratorX86* const codegen_;
137   InvokeDexCallingConventionVisitorX86 parameter_visitor_;
138 
139   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86);
140 };
141 
142 class InstructionCodeGeneratorX86 : public HGraphVisitor {
143  public:
144   InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen);
145 
146 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
147   void Visit##name(H##name* instr) OVERRIDE;
148 
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)149   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
150 
151 #undef DECLARE_VISIT_INSTRUCTION
152 
153   X86Assembler* GetAssembler() const { return assembler_; }
154 
155  private:
156   // Generate code for the given suspend check. If not null, `successor`
157   // is the block to branch to if the suspend check is not needed, and after
158   // the suspend call.
159   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
160   void GenerateClassInitializationCheck(SlowPathCodeX86* slow_path, Register class_reg);
161   void HandleBitwiseOperation(HBinaryOperation* instruction);
162   void GenerateDivRemIntegral(HBinaryOperation* instruction);
163   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
164   void DivByPowerOfTwo(HDiv* instruction);
165   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
166   void GenerateRemFP(HRem *rem);
167   void HandleShift(HBinaryOperation* instruction);
168   void GenerateShlLong(const Location& loc, Register shifter);
169   void GenerateShrLong(const Location& loc, Register shifter);
170   void GenerateUShrLong(const Location& loc, Register shifter);
171   void GenerateShlLong(const Location& loc, int shift);
172   void GenerateShrLong(const Location& loc, int shift);
173   void GenerateUShrLong(const Location& loc, int shift);
174   void GenerateMemoryBarrier(MemBarrierKind kind);
175   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
176   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
177   // Push value to FPU stack. `is_fp` specifies whether the value is floating point or not.
178   // `is_wide` specifies whether it is long/double or not.
179   void PushOntoFPStack(Location source, uint32_t temp_offset,
180                        uint32_t stack_adjustment, bool is_fp, bool is_wide);
181 
182   void GenerateImplicitNullCheck(HNullCheck* instruction);
183   void GenerateExplicitNullCheck(HNullCheck* instruction);
184   void GenerateTestAndBranch(HInstruction* instruction,
185                              Label* true_target,
186                              Label* false_target,
187                              Label* always_true_target);
188 
189   X86Assembler* const assembler_;
190   CodeGeneratorX86* const codegen_;
191 
192   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86);
193 };
194 
195 class CodeGeneratorX86 : public CodeGenerator {
196  public:
197   CodeGeneratorX86(HGraph* graph,
198                    const X86InstructionSetFeatures& isa_features,
199                    const CompilerOptions& compiler_options);
~CodeGeneratorX86()200   virtual ~CodeGeneratorX86() {}
201 
202   void GenerateFrameEntry() OVERRIDE;
203   void GenerateFrameExit() OVERRIDE;
204   void Bind(HBasicBlock* block) OVERRIDE;
205   void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
206   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
207   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
208   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
209   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
210 
GetWordSize()211   size_t GetWordSize() const OVERRIDE {
212     return kX86WordSize;
213   }
214 
GetFloatingPointSpillSlotSize()215   size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
216     // 8 bytes == 2 words for each spill.
217     return 2 * kX86WordSize;
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   X86Assembler* GetAssembler() OVERRIDE {
229     return &assembler_;
230   }
231 
GetAddressOf(HBasicBlock * block)232   uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
233     return GetLabelOf(block)->Position();
234   }
235 
236   void SetupBlockedRegisters(bool is_baseline) const OVERRIDE;
237 
238   Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
239 
240   Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
241 
242   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
243   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
244 
245   // Blocks all register pairs made out of blocked core registers.
246   void UpdateBlockedPairRegisters() const;
247 
GetMoveResolver()248   ParallelMoveResolverX86* GetMoveResolver() OVERRIDE {
249     return &move_resolver_;
250   }
251 
GetInstructionSet()252   InstructionSet GetInstructionSet() const OVERRIDE {
253     return InstructionSet::kX86;
254   }
255 
256   // Helper method to move a 32bits value between two locations.
257   void Move32(Location destination, Location source);
258   // Helper method to move a 64bits value between two locations.
259   void Move64(Location destination, Location source);
260 
261   // Generate a call to a static or direct method.
262   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp);
263 
264   // Emit a write barrier.
265   void MarkGCCard(Register temp, Register card, Register object, Register value);
266 
267   void LoadCurrentMethod(Register reg);
268 
GetLabelOf(HBasicBlock * block)269   Label* GetLabelOf(HBasicBlock* block) const {
270     return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
271   }
272 
Initialize()273   void Initialize() OVERRIDE {
274     block_labels_.SetSize(GetGraph()->GetBlocks().Size());
275   }
276 
NeedsTwoRegisters(Primitive::Type type)277   bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE {
278     return type == Primitive::kPrimLong;
279   }
280 
ShouldSplitLongMoves()281   bool ShouldSplitLongMoves() const OVERRIDE { return true; }
282 
GetFrameEntryLabel()283   Label* GetFrameEntryLabel() { return &frame_entry_label_; }
284 
GetInstructionSetFeatures()285   const X86InstructionSetFeatures& GetInstructionSetFeatures() const {
286     return isa_features_;
287   }
288 
289  private:
290   // Labels for each block that will be compiled.
291   GrowableArray<Label> block_labels_;
292   Label frame_entry_label_;
293   LocationsBuilderX86 location_builder_;
294   InstructionCodeGeneratorX86 instruction_visitor_;
295   ParallelMoveResolverX86 move_resolver_;
296   X86Assembler assembler_;
297   const X86InstructionSetFeatures& isa_features_;
298 
299   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86);
300 };
301 
302 class SlowPathCodeX86 : public SlowPathCode {
303  public:
SlowPathCodeX86()304   SlowPathCodeX86() : entry_label_(), exit_label_() {}
305 
GetEntryLabel()306   Label* GetEntryLabel() { return &entry_label_; }
GetExitLabel()307   Label* GetExitLabel() { return &exit_label_; }
308 
309  private:
310   Label entry_label_;
311   Label exit_label_;
312 
313   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeX86);
314 };
315 
316 }  // namespace x86
317 }  // namespace art
318 
319 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_H_
320