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