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