code_generator_x86_64.h revision 225b6464a58ebe11c156144653f11a1c6607f4eb
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 27namespace art { 28namespace x86_64 { 29 30// Use a local definition to prevent copying mistakes. 31static constexpr size_t kX86_64WordSize = kX86_64PointerSize; 32 33static constexpr Register kParameterCoreRegisters[] = { RSI, RDX, RCX, R8, R9 }; 34static constexpr FloatRegister kParameterFloatRegisters[] = 35 { XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7 }; 36 37static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 38static constexpr size_t kParameterFloatRegistersLength = arraysize(kParameterFloatRegisters); 39 40static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX, RCX }; 41static constexpr size_t kRuntimeParameterCoreRegistersLength = 42 arraysize(kRuntimeParameterCoreRegisters); 43static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1 }; 44static constexpr size_t kRuntimeParameterFpuRegistersLength = 45 arraysize(kRuntimeParameterFpuRegisters); 46 47class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> { 48 public: 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 60class InvokeDexCallingConvention : public CallingConvention<Register, FloatRegister> { 61 public: 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 73class InvokeDexCallingConventionVisitorX86_64 : public InvokeDexCallingConventionVisitor { 74 public: 75 InvokeDexCallingConventionVisitorX86_64() {} 76 virtual ~InvokeDexCallingConventionVisitorX86_64() {} 77 78 Location GetNextLocation(Primitive::Type type) OVERRIDE; 79 Location GetReturnLocation(Primitive::Type type) const OVERRIDE; 80 Location GetMethodLocation() const OVERRIDE; 81 82 private: 83 InvokeDexCallingConvention calling_convention; 84 85 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorX86_64); 86}; 87 88class CodeGeneratorX86_64; 89 90class ParallelMoveResolverX86_64 : public ParallelMoveResolverWithSwap { 91 public: 92 ParallelMoveResolverX86_64(ArenaAllocator* allocator, CodeGeneratorX86_64* codegen) 93 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} 94 95 void EmitMove(size_t index) OVERRIDE; 96 void EmitSwap(size_t index) OVERRIDE; 97 void SpillScratch(int reg) OVERRIDE; 98 void RestoreScratch(int reg) OVERRIDE; 99 100 X86_64Assembler* GetAssembler() const; 101 102 private: 103 void Exchange32(CpuRegister reg, int mem); 104 void Exchange32(XmmRegister reg, int mem); 105 void Exchange32(int mem1, int mem2); 106 void Exchange64(CpuRegister reg, int mem); 107 void Exchange64(XmmRegister reg, int mem); 108 void Exchange64(int mem1, int mem2); 109 110 CodeGeneratorX86_64* const codegen_; 111 112 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverX86_64); 113}; 114 115class LocationsBuilderX86_64 : public HGraphVisitor { 116 public: 117 LocationsBuilderX86_64(HGraph* graph, CodeGeneratorX86_64* codegen) 118 : HGraphVisitor(graph), codegen_(codegen) {} 119 120#define DECLARE_VISIT_INSTRUCTION(name, super) \ 121 void Visit##name(H##name* instr) OVERRIDE; 122 123 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) 124 FOR_EACH_CONCRETE_INSTRUCTION_X86_64(DECLARE_VISIT_INSTRUCTION) 125 126#undef DECLARE_VISIT_INSTRUCTION 127 128 void VisitInstruction(HInstruction* instruction) OVERRIDE { 129 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 130 << " (id " << instruction->GetId() << ")"; 131 } 132 133 private: 134 void HandleInvoke(HInvoke* invoke); 135 void HandleBitwiseOperation(HBinaryOperation* operation); 136 void HandleShift(HBinaryOperation* operation); 137 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); 138 void HandleFieldGet(HInstruction* instruction); 139 140 CodeGeneratorX86_64* const codegen_; 141 InvokeDexCallingConventionVisitorX86_64 parameter_visitor_; 142 143 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86_64); 144}; 145 146class InstructionCodeGeneratorX86_64 : public HGraphVisitor { 147 public: 148 InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen); 149 150#define DECLARE_VISIT_INSTRUCTION(name, super) \ 151 void Visit##name(H##name* instr) OVERRIDE; 152 153 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) 154 FOR_EACH_CONCRETE_INSTRUCTION_X86_64(DECLARE_VISIT_INSTRUCTION) 155 156#undef DECLARE_VISIT_INSTRUCTION 157 158 void VisitInstruction(HInstruction* instruction) OVERRIDE { 159 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 160 << " (id " << instruction->GetId() << ")"; 161 } 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(SlowPathCode* 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, 180 const FieldInfo& field_info, 181 bool value_can_be_null); 182 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 183 void GenerateImplicitNullCheck(HNullCheck* instruction); 184 void GenerateExplicitNullCheck(HNullCheck* instruction); 185 void PushOntoFPStack(Location source, uint32_t temp_offset, 186 uint32_t stack_adjustment, bool is_float); 187 void GenerateTestAndBranch(HInstruction* instruction, 188 Label* true_target, 189 Label* false_target, 190 Label* always_true_target); 191 void GenerateCompareTestAndBranch(HIf* if_inst, 192 HCondition* condition, 193 Label* true_target, 194 Label* false_target, 195 Label* always_true_target); 196 void GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label); 197 void HandleGoto(HInstruction* got, HBasicBlock* successor); 198 199 X86_64Assembler* const assembler_; 200 CodeGeneratorX86_64* const codegen_; 201 202 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86_64); 203}; 204 205class CodeGeneratorX86_64 : public CodeGenerator { 206 public: 207 CodeGeneratorX86_64(HGraph* graph, 208 const X86_64InstructionSetFeatures& isa_features, 209 const CompilerOptions& compiler_options, 210 OptimizingCompilerStats* stats = nullptr); 211 virtual ~CodeGeneratorX86_64() {} 212 213 void GenerateFrameEntry() OVERRIDE; 214 void GenerateFrameExit() OVERRIDE; 215 void Bind(HBasicBlock* block) OVERRIDE; 216 void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; 217 void MoveConstant(Location destination, int32_t value) OVERRIDE; 218 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 219 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 220 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 221 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 222 223 // Generate code to invoke a runtime entry point. 224 void InvokeRuntime(QuickEntrypointEnum entrypoint, 225 HInstruction* instruction, 226 uint32_t dex_pc, 227 SlowPathCode* slow_path) OVERRIDE; 228 229 void InvokeRuntime(int32_t entry_point_offset, 230 HInstruction* instruction, 231 uint32_t dex_pc, 232 SlowPathCode* slow_path); 233 234 size_t GetWordSize() const OVERRIDE { 235 return kX86_64WordSize; 236 } 237 238 size_t GetFloatingPointSpillSlotSize() const OVERRIDE { 239 return kX86_64WordSize; 240 } 241 242 HGraphVisitor* GetLocationBuilder() OVERRIDE { 243 return &location_builder_; 244 } 245 246 HGraphVisitor* GetInstructionVisitor() OVERRIDE { 247 return &instruction_visitor_; 248 } 249 250 X86_64Assembler* GetAssembler() OVERRIDE { 251 return &assembler_; 252 } 253 254 const X86_64Assembler& GetAssembler() const OVERRIDE { 255 return assembler_; 256 } 257 258 ParallelMoveResolverX86_64* GetMoveResolver() OVERRIDE { 259 return &move_resolver_; 260 } 261 262 uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE { 263 return GetLabelOf(block)->Position(); 264 } 265 266 Location GetStackLocation(HLoadLocal* load) const OVERRIDE; 267 268 void SetupBlockedRegisters(bool is_baseline) const OVERRIDE; 269 Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE; 270 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; 271 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; 272 void Finalize(CodeAllocator* allocator) OVERRIDE; 273 274 InstructionSet GetInstructionSet() const OVERRIDE { 275 return InstructionSet::kX86_64; 276 } 277 278 // Emit a write barrier. 279 void MarkGCCard(CpuRegister temp, 280 CpuRegister card, 281 CpuRegister object, 282 CpuRegister value, 283 bool value_can_be_null); 284 285 // Helper method to move a value between two locations. 286 void Move(Location destination, Location source); 287 288 Label* GetLabelOf(HBasicBlock* block) const { 289 return CommonGetLabelOf<Label>(block_labels_, block); 290 } 291 292 void Initialize() OVERRIDE { 293 block_labels_ = CommonInitializeLabels<Label>(); 294 } 295 296 bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 297 return false; 298 } 299 300 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; 301 void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; 302 303 void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE; 304 305 void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE; 306 307 const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const { 308 return isa_features_; 309 } 310 311 int ConstantAreaStart() const { 312 return constant_area_start_; 313 } 314 315 Address LiteralDoubleAddress(double v); 316 Address LiteralFloatAddress(float v); 317 Address LiteralInt32Address(int32_t v); 318 Address LiteralInt64Address(int64_t v); 319 320 // Load a 64 bit value into a register in the most efficient manner. 321 void Load64BitValue(CpuRegister dest, int64_t value); 322 323 // Store a 64 bit value into a DoubleStackSlot in the most efficient manner. 324 void Store64BitValueToStack(Location dest, int64_t value); 325 326 private: 327 struct PcRelativeDexCacheAccessInfo { 328 PcRelativeDexCacheAccessInfo(const DexFile& dex_file, uint32_t element_off) 329 : target_dex_file(dex_file), element_offset(element_off), label() { } 330 331 const DexFile& target_dex_file; 332 uint32_t element_offset; 333 Label label; 334 }; 335 336 // Labels for each block that will be compiled. 337 Label* block_labels_; // Indexed by block id. 338 Label frame_entry_label_; 339 LocationsBuilderX86_64 location_builder_; 340 InstructionCodeGeneratorX86_64 instruction_visitor_; 341 ParallelMoveResolverX86_64 move_resolver_; 342 X86_64Assembler assembler_; 343 const X86_64InstructionSetFeatures& isa_features_; 344 345 // Offset to the start of the constant area in the assembled code. 346 // Used for fixups to the constant area. 347 int constant_area_start_; 348 349 // Method patch info. Using ArenaDeque<> which retains element addresses on push/emplace_back(). 350 ArenaDeque<MethodPatchInfo<Label>> method_patches_; 351 ArenaDeque<MethodPatchInfo<Label>> relative_call_patches_; 352 // PC-relative DexCache access info. 353 ArenaDeque<PcRelativeDexCacheAccessInfo> pc_rel_dex_cache_patches_; 354 355 // When we don't know the proper offset for the value, we use kDummy32BitOffset. 356 // We will fix this up in the linker later to have the right value. 357 static constexpr int32_t kDummy32BitOffset = 256; 358 359 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86_64); 360}; 361 362} // namespace x86_64 363} // namespace art 364 365#endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_64_H_ 366