code_generator_x86_64.h revision e460d1df1f789c7c8bb97024a8efbd713ac175e9
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 FieldAccessCallingConventionX86_64 : public FieldAccessCallingConvention { 74 public: 75 FieldAccessCallingConventionX86_64() {} 76 77 Location GetObjectLocation() const OVERRIDE { 78 return Location::RegisterLocation(RSI); 79 } 80 Location GetFieldIndexLocation() const OVERRIDE { 81 return Location::RegisterLocation(RDI); 82 } 83 Location GetReturnLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 84 return Location::RegisterLocation(RAX); 85 } 86 Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE { 87 return Primitive::Is64BitType(type) 88 ? Location::RegisterLocation(RDX) 89 : (is_instance 90 ? Location::RegisterLocation(RDX) 91 : Location::RegisterLocation(RSI)); 92 } 93 Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 94 return Location::FpuRegisterLocation(XMM0); 95 } 96 97 private: 98 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionX86_64); 99}; 100 101 102class InvokeDexCallingConventionVisitorX86_64 : public InvokeDexCallingConventionVisitor { 103 public: 104 InvokeDexCallingConventionVisitorX86_64() {} 105 virtual ~InvokeDexCallingConventionVisitorX86_64() {} 106 107 Location GetNextLocation(Primitive::Type type) OVERRIDE; 108 Location GetReturnLocation(Primitive::Type type) const OVERRIDE; 109 Location GetMethodLocation() const OVERRIDE; 110 111 private: 112 InvokeDexCallingConvention calling_convention; 113 114 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorX86_64); 115}; 116 117class CodeGeneratorX86_64; 118 119class ParallelMoveResolverX86_64 : public ParallelMoveResolverWithSwap { 120 public: 121 ParallelMoveResolverX86_64(ArenaAllocator* allocator, CodeGeneratorX86_64* codegen) 122 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} 123 124 void EmitMove(size_t index) OVERRIDE; 125 void EmitSwap(size_t index) OVERRIDE; 126 void SpillScratch(int reg) OVERRIDE; 127 void RestoreScratch(int reg) OVERRIDE; 128 129 X86_64Assembler* GetAssembler() const; 130 131 private: 132 void Exchange32(CpuRegister reg, int mem); 133 void Exchange32(XmmRegister reg, int mem); 134 void Exchange32(int mem1, int mem2); 135 void Exchange64(CpuRegister reg, int mem); 136 void Exchange64(XmmRegister reg, int mem); 137 void Exchange64(int mem1, int mem2); 138 139 CodeGeneratorX86_64* const codegen_; 140 141 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverX86_64); 142}; 143 144class LocationsBuilderX86_64 : public HGraphVisitor { 145 public: 146 LocationsBuilderX86_64(HGraph* graph, CodeGeneratorX86_64* codegen) 147 : HGraphVisitor(graph), codegen_(codegen) {} 148 149#define DECLARE_VISIT_INSTRUCTION(name, super) \ 150 void Visit##name(H##name* instr) OVERRIDE; 151 152 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) 153 FOR_EACH_CONCRETE_INSTRUCTION_X86_64(DECLARE_VISIT_INSTRUCTION) 154 155#undef DECLARE_VISIT_INSTRUCTION 156 157 void VisitInstruction(HInstruction* instruction) OVERRIDE { 158 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 159 << " (id " << instruction->GetId() << ")"; 160 } 161 162 private: 163 void HandleInvoke(HInvoke* invoke); 164 void HandleBitwiseOperation(HBinaryOperation* operation); 165 void HandleShift(HBinaryOperation* operation); 166 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); 167 void HandleFieldGet(HInstruction* instruction); 168 169 CodeGeneratorX86_64* const codegen_; 170 InvokeDexCallingConventionVisitorX86_64 parameter_visitor_; 171 172 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86_64); 173}; 174 175class InstructionCodeGeneratorX86_64 : public HGraphVisitor { 176 public: 177 InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen); 178 179#define DECLARE_VISIT_INSTRUCTION(name, super) \ 180 void Visit##name(H##name* instr) OVERRIDE; 181 182 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) 183 FOR_EACH_CONCRETE_INSTRUCTION_X86_64(DECLARE_VISIT_INSTRUCTION) 184 185#undef DECLARE_VISIT_INSTRUCTION 186 187 void VisitInstruction(HInstruction* instruction) OVERRIDE { 188 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 189 << " (id " << instruction->GetId() << ")"; 190 } 191 192 X86_64Assembler* GetAssembler() const { return assembler_; } 193 194 private: 195 // Generate code for the given suspend check. If not null, `successor` 196 // is the block to branch to if the suspend check is not needed, and after 197 // the suspend call. 198 void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); 199 void GenerateClassInitializationCheck(SlowPathCode* slow_path, CpuRegister class_reg); 200 void HandleBitwiseOperation(HBinaryOperation* operation); 201 void GenerateRemFP(HRem* rem); 202 void DivRemOneOrMinusOne(HBinaryOperation* instruction); 203 void DivByPowerOfTwo(HDiv* instruction); 204 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); 205 void GenerateDivRemIntegral(HBinaryOperation* instruction); 206 void HandleShift(HBinaryOperation* operation); 207 void GenerateMemoryBarrier(MemBarrierKind kind); 208 void HandleFieldSet(HInstruction* instruction, 209 const FieldInfo& field_info, 210 bool value_can_be_null); 211 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 212 void GenerateImplicitNullCheck(HNullCheck* instruction); 213 void GenerateExplicitNullCheck(HNullCheck* instruction); 214 void PushOntoFPStack(Location source, uint32_t temp_offset, 215 uint32_t stack_adjustment, bool is_float); 216 void GenerateTestAndBranch(HInstruction* instruction, 217 Label* true_target, 218 Label* false_target, 219 Label* always_true_target); 220 void GenerateCompareTestAndBranch(HIf* if_inst, 221 HCondition* condition, 222 Label* true_target, 223 Label* false_target, 224 Label* always_true_target); 225 void GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label); 226 void HandleGoto(HInstruction* got, HBasicBlock* successor); 227 228 X86_64Assembler* const assembler_; 229 CodeGeneratorX86_64* const codegen_; 230 231 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86_64); 232}; 233 234class CodeGeneratorX86_64 : public CodeGenerator { 235 public: 236 CodeGeneratorX86_64(HGraph* graph, 237 const X86_64InstructionSetFeatures& isa_features, 238 const CompilerOptions& compiler_options, 239 OptimizingCompilerStats* stats = nullptr); 240 virtual ~CodeGeneratorX86_64() {} 241 242 void GenerateFrameEntry() OVERRIDE; 243 void GenerateFrameExit() OVERRIDE; 244 void Bind(HBasicBlock* block) OVERRIDE; 245 void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; 246 void MoveConstant(Location destination, int32_t value) OVERRIDE; 247 void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE; 248 void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE; 249 250 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 251 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 252 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 253 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 254 255 // Generate code to invoke a runtime entry point. 256 void InvokeRuntime(QuickEntrypointEnum entrypoint, 257 HInstruction* instruction, 258 uint32_t dex_pc, 259 SlowPathCode* slow_path) OVERRIDE; 260 261 void InvokeRuntime(int32_t entry_point_offset, 262 HInstruction* instruction, 263 uint32_t dex_pc, 264 SlowPathCode* slow_path); 265 266 size_t GetWordSize() const OVERRIDE { 267 return kX86_64WordSize; 268 } 269 270 size_t GetFloatingPointSpillSlotSize() const OVERRIDE { 271 return kX86_64WordSize; 272 } 273 274 HGraphVisitor* GetLocationBuilder() OVERRIDE { 275 return &location_builder_; 276 } 277 278 HGraphVisitor* GetInstructionVisitor() OVERRIDE { 279 return &instruction_visitor_; 280 } 281 282 X86_64Assembler* GetAssembler() OVERRIDE { 283 return &assembler_; 284 } 285 286 const X86_64Assembler& GetAssembler() const OVERRIDE { 287 return assembler_; 288 } 289 290 ParallelMoveResolverX86_64* GetMoveResolver() OVERRIDE { 291 return &move_resolver_; 292 } 293 294 uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE { 295 return GetLabelOf(block)->Position(); 296 } 297 298 Location GetStackLocation(HLoadLocal* load) const OVERRIDE; 299 300 void SetupBlockedRegisters(bool is_baseline) const OVERRIDE; 301 Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE; 302 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; 303 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; 304 void Finalize(CodeAllocator* allocator) OVERRIDE; 305 306 InstructionSet GetInstructionSet() const OVERRIDE { 307 return InstructionSet::kX86_64; 308 } 309 310 // Emit a write barrier. 311 void MarkGCCard(CpuRegister temp, 312 CpuRegister card, 313 CpuRegister object, 314 CpuRegister value, 315 bool value_can_be_null); 316 317 // Helper method to move a value between two locations. 318 void Move(Location destination, Location source); 319 320 Label* GetLabelOf(HBasicBlock* block) const { 321 return CommonGetLabelOf<Label>(block_labels_, block); 322 } 323 324 void Initialize() OVERRIDE { 325 block_labels_ = CommonInitializeLabels<Label>(); 326 } 327 328 bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 329 return false; 330 } 331 332 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; 333 void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; 334 335 void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE; 336 337 void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE; 338 339 const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const { 340 return isa_features_; 341 } 342 343 int ConstantAreaStart() const { 344 return constant_area_start_; 345 } 346 347 Address LiteralDoubleAddress(double v); 348 Address LiteralFloatAddress(float v); 349 Address LiteralInt32Address(int32_t v); 350 Address LiteralInt64Address(int64_t v); 351 352 // Load a 64 bit value into a register in the most efficient manner. 353 void Load64BitValue(CpuRegister dest, int64_t value); 354 355 // Store a 64 bit value into a DoubleStackSlot in the most efficient manner. 356 void Store64BitValueToStack(Location dest, int64_t value); 357 358 private: 359 struct PcRelativeDexCacheAccessInfo { 360 PcRelativeDexCacheAccessInfo(const DexFile& dex_file, uint32_t element_off) 361 : target_dex_file(dex_file), element_offset(element_off), label() { } 362 363 const DexFile& target_dex_file; 364 uint32_t element_offset; 365 Label label; 366 }; 367 368 // Labels for each block that will be compiled. 369 Label* block_labels_; // Indexed by block id. 370 Label frame_entry_label_; 371 LocationsBuilderX86_64 location_builder_; 372 InstructionCodeGeneratorX86_64 instruction_visitor_; 373 ParallelMoveResolverX86_64 move_resolver_; 374 X86_64Assembler assembler_; 375 const X86_64InstructionSetFeatures& isa_features_; 376 377 // Offset to the start of the constant area in the assembled code. 378 // Used for fixups to the constant area. 379 int constant_area_start_; 380 381 // Method patch info. Using ArenaDeque<> which retains element addresses on push/emplace_back(). 382 ArenaDeque<MethodPatchInfo<Label>> method_patches_; 383 ArenaDeque<MethodPatchInfo<Label>> relative_call_patches_; 384 // PC-relative DexCache access info. 385 ArenaDeque<PcRelativeDexCacheAccessInfo> pc_rel_dex_cache_patches_; 386 387 // When we don't know the proper offset for the value, we use kDummy32BitOffset. 388 // We will fix this up in the linker later to have the right value. 389 static constexpr int32_t kDummy32BitOffset = 256; 390 391 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86_64); 392}; 393 394} // namespace x86_64 395} // namespace art 396 397#endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_64_H_ 398