code_generator_x86_64.h revision 0d5a281c671444bfa75d63caf1427a8c0e6e1177
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 33// Some x86_64 instructions require a register to be available as temp. 34static constexpr Register TMP = R11; 35 36static constexpr Register kParameterCoreRegisters[] = { RSI, RDX, RCX, R8, R9 }; 37static constexpr FloatRegister kParameterFloatRegisters[] = 38 { XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7 }; 39 40static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 41static constexpr size_t kParameterFloatRegistersLength = arraysize(kParameterFloatRegisters); 42 43static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX, RCX }; 44static constexpr size_t kRuntimeParameterCoreRegistersLength = 45 arraysize(kRuntimeParameterCoreRegisters); 46static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1 }; 47static constexpr size_t kRuntimeParameterFpuRegistersLength = 48 arraysize(kRuntimeParameterFpuRegisters); 49 50class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> { 51 public: 52 InvokeRuntimeCallingConvention() 53 : CallingConvention(kRuntimeParameterCoreRegisters, 54 kRuntimeParameterCoreRegistersLength, 55 kRuntimeParameterFpuRegisters, 56 kRuntimeParameterFpuRegistersLength, 57 kX86_64PointerSize) {} 58 59 private: 60 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 61}; 62 63class InvokeDexCallingConvention : public CallingConvention<Register, FloatRegister> { 64 public: 65 InvokeDexCallingConvention() : CallingConvention( 66 kParameterCoreRegisters, 67 kParameterCoreRegistersLength, 68 kParameterFloatRegisters, 69 kParameterFloatRegistersLength, 70 kX86_64PointerSize) {} 71 72 private: 73 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); 74}; 75 76class FieldAccessCallingConventionX86_64 : public FieldAccessCallingConvention { 77 public: 78 FieldAccessCallingConventionX86_64() {} 79 80 Location GetObjectLocation() const OVERRIDE { 81 return Location::RegisterLocation(RSI); 82 } 83 Location GetFieldIndexLocation() const OVERRIDE { 84 return Location::RegisterLocation(RDI); 85 } 86 Location GetReturnLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 87 return Location::RegisterLocation(RAX); 88 } 89 Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE { 90 return Primitive::Is64BitType(type) 91 ? Location::RegisterLocation(RDX) 92 : (is_instance 93 ? Location::RegisterLocation(RDX) 94 : Location::RegisterLocation(RSI)); 95 } 96 Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 97 return Location::FpuRegisterLocation(XMM0); 98 } 99 100 private: 101 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionX86_64); 102}; 103 104 105class InvokeDexCallingConventionVisitorX86_64 : public InvokeDexCallingConventionVisitor { 106 public: 107 InvokeDexCallingConventionVisitorX86_64() {} 108 virtual ~InvokeDexCallingConventionVisitorX86_64() {} 109 110 Location GetNextLocation(Primitive::Type type) OVERRIDE; 111 Location GetReturnLocation(Primitive::Type type) const OVERRIDE; 112 Location GetMethodLocation() const OVERRIDE; 113 114 private: 115 InvokeDexCallingConvention calling_convention; 116 117 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorX86_64); 118}; 119 120class CodeGeneratorX86_64; 121 122class ParallelMoveResolverX86_64 : public ParallelMoveResolverWithSwap { 123 public: 124 ParallelMoveResolverX86_64(ArenaAllocator* allocator, CodeGeneratorX86_64* codegen) 125 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} 126 127 void EmitMove(size_t index) OVERRIDE; 128 void EmitSwap(size_t index) OVERRIDE; 129 void SpillScratch(int reg) OVERRIDE; 130 void RestoreScratch(int reg) OVERRIDE; 131 132 X86_64Assembler* GetAssembler() const; 133 134 private: 135 void Exchange32(CpuRegister reg, int mem); 136 void Exchange32(XmmRegister reg, int mem); 137 void Exchange32(int mem1, int mem2); 138 void Exchange64(CpuRegister reg, int mem); 139 void Exchange64(XmmRegister reg, int mem); 140 void Exchange64(int mem1, int mem2); 141 142 CodeGeneratorX86_64* const codegen_; 143 144 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverX86_64); 145}; 146 147class LocationsBuilderX86_64 : public HGraphVisitor { 148 public: 149 LocationsBuilderX86_64(HGraph* graph, CodeGeneratorX86_64* codegen) 150 : HGraphVisitor(graph), codegen_(codegen) {} 151 152#define DECLARE_VISIT_INSTRUCTION(name, super) \ 153 void Visit##name(H##name* instr) OVERRIDE; 154 155 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) 156 FOR_EACH_CONCRETE_INSTRUCTION_X86_64(DECLARE_VISIT_INSTRUCTION) 157 158#undef DECLARE_VISIT_INSTRUCTION 159 160 void VisitInstruction(HInstruction* instruction) OVERRIDE { 161 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 162 << " (id " << instruction->GetId() << ")"; 163 } 164 165 private: 166 void HandleInvoke(HInvoke* invoke); 167 void HandleBitwiseOperation(HBinaryOperation* operation); 168 void HandleShift(HBinaryOperation* operation); 169 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); 170 void HandleFieldGet(HInstruction* instruction); 171 172 CodeGeneratorX86_64* const codegen_; 173 InvokeDexCallingConventionVisitorX86_64 parameter_visitor_; 174 175 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86_64); 176}; 177 178class InstructionCodeGeneratorX86_64 : public HGraphVisitor { 179 public: 180 InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen); 181 182#define DECLARE_VISIT_INSTRUCTION(name, super) \ 183 void Visit##name(H##name* instr) OVERRIDE; 184 185 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) 186 FOR_EACH_CONCRETE_INSTRUCTION_X86_64(DECLARE_VISIT_INSTRUCTION) 187 188#undef DECLARE_VISIT_INSTRUCTION 189 190 void VisitInstruction(HInstruction* instruction) OVERRIDE { 191 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 192 << " (id " << instruction->GetId() << ")"; 193 } 194 195 X86_64Assembler* GetAssembler() const { return assembler_; } 196 197 private: 198 // Generate code for the given suspend check. If not null, `successor` 199 // is the block to branch to if the suspend check is not needed, and after 200 // the suspend call. 201 void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); 202 void GenerateClassInitializationCheck(SlowPathCode* slow_path, CpuRegister class_reg); 203 void HandleBitwiseOperation(HBinaryOperation* operation); 204 void GenerateRemFP(HRem* rem); 205 void DivRemOneOrMinusOne(HBinaryOperation* instruction); 206 void DivByPowerOfTwo(HDiv* instruction); 207 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); 208 void GenerateDivRemIntegral(HBinaryOperation* instruction); 209 void HandleShift(HBinaryOperation* operation); 210 void GenerateMemoryBarrier(MemBarrierKind kind); 211 void HandleFieldSet(HInstruction* instruction, 212 const FieldInfo& field_info, 213 bool value_can_be_null); 214 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 215 void GenerateImplicitNullCheck(HNullCheck* instruction); 216 void GenerateExplicitNullCheck(HNullCheck* instruction); 217 void PushOntoFPStack(Location source, uint32_t temp_offset, 218 uint32_t stack_adjustment, bool is_float); 219 void GenerateTestAndBranch(HInstruction* instruction, 220 Label* true_target, 221 Label* false_target, 222 Label* always_true_target); 223 void GenerateCompareTestAndBranch(HIf* if_inst, 224 HCondition* condition, 225 Label* true_target, 226 Label* false_target, 227 Label* always_true_target); 228 void GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label); 229 void HandleGoto(HInstruction* got, HBasicBlock* successor); 230 231 X86_64Assembler* const assembler_; 232 CodeGeneratorX86_64* const codegen_; 233 234 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86_64); 235}; 236 237// Class for fixups to jump tables. 238class JumpTableRIPFixup; 239 240class CodeGeneratorX86_64 : public CodeGenerator { 241 public: 242 CodeGeneratorX86_64(HGraph* graph, 243 const X86_64InstructionSetFeatures& isa_features, 244 const CompilerOptions& compiler_options, 245 OptimizingCompilerStats* stats = nullptr); 246 virtual ~CodeGeneratorX86_64() {} 247 248 void GenerateFrameEntry() OVERRIDE; 249 void GenerateFrameExit() OVERRIDE; 250 void Bind(HBasicBlock* block) OVERRIDE; 251 void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; 252 void MoveConstant(Location destination, int32_t value) OVERRIDE; 253 void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE; 254 void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE; 255 256 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 257 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 258 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 259 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 260 261 // Generate code to invoke a runtime entry point. 262 void InvokeRuntime(QuickEntrypointEnum entrypoint, 263 HInstruction* instruction, 264 uint32_t dex_pc, 265 SlowPathCode* slow_path) OVERRIDE; 266 267 void InvokeRuntime(int32_t entry_point_offset, 268 HInstruction* instruction, 269 uint32_t dex_pc, 270 SlowPathCode* slow_path); 271 272 size_t GetWordSize() const OVERRIDE { 273 return kX86_64WordSize; 274 } 275 276 size_t GetFloatingPointSpillSlotSize() const OVERRIDE { 277 return kX86_64WordSize; 278 } 279 280 HGraphVisitor* GetLocationBuilder() OVERRIDE { 281 return &location_builder_; 282 } 283 284 HGraphVisitor* GetInstructionVisitor() OVERRIDE { 285 return &instruction_visitor_; 286 } 287 288 X86_64Assembler* GetAssembler() OVERRIDE { 289 return &assembler_; 290 } 291 292 const X86_64Assembler& GetAssembler() const OVERRIDE { 293 return assembler_; 294 } 295 296 ParallelMoveResolverX86_64* GetMoveResolver() OVERRIDE { 297 return &move_resolver_; 298 } 299 300 uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE { 301 return GetLabelOf(block)->Position(); 302 } 303 304 Location GetStackLocation(HLoadLocal* load) const OVERRIDE; 305 306 void SetupBlockedRegisters(bool is_baseline) const OVERRIDE; 307 Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE; 308 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; 309 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; 310 void Finalize(CodeAllocator* allocator) OVERRIDE; 311 312 InstructionSet GetInstructionSet() const OVERRIDE { 313 return InstructionSet::kX86_64; 314 } 315 316 // Emit a write barrier. 317 void MarkGCCard(CpuRegister temp, 318 CpuRegister card, 319 CpuRegister object, 320 CpuRegister value, 321 bool value_can_be_null); 322 323 // Helper method to move a value between two locations. 324 void Move(Location destination, Location source); 325 326 Label* GetLabelOf(HBasicBlock* block) const { 327 return CommonGetLabelOf<Label>(block_labels_, block); 328 } 329 330 void Initialize() OVERRIDE { 331 block_labels_ = CommonInitializeLabels<Label>(); 332 } 333 334 bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 335 return false; 336 } 337 338 // Check if the desired_dispatch_info is supported. If it is, return it, 339 // otherwise return a fall-back info that should be used instead. 340 HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( 341 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, 342 MethodReference target_method) OVERRIDE; 343 344 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; 345 void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; 346 347 void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE; 348 349 void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE; 350 351 const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const { 352 return isa_features_; 353 } 354 355 // Generate a read barrier for a heap reference within `instruction`. 356 // 357 // A read barrier for an object reference read from the heap is 358 // implemented as a call to the artReadBarrierSlow runtime entry 359 // point, which is passed the values in locations `ref`, `obj`, and 360 // `offset`: 361 // 362 // mirror::Object* artReadBarrierSlow(mirror::Object* ref, 363 // mirror::Object* obj, 364 // uint32_t offset); 365 // 366 // The `out` location contains the value returned by 367 // artReadBarrierSlow. 368 // 369 // When `index` provided (i.e., when it is different from 370 // Location::NoLocation()), the offset value passed to 371 // artReadBarrierSlow is adjusted to take `index` into account. 372 void GenerateReadBarrier(HInstruction* instruction, 373 Location out, 374 Location ref, 375 Location obj, 376 uint32_t offset, 377 Location index = Location::NoLocation()); 378 379 // If read barriers are enabled, generate a read barrier for a heap reference. 380 // If heap poisoning is enabled, also unpoison the reference in `out`. 381 void MaybeGenerateReadBarrier(HInstruction* instruction, 382 Location out, 383 Location ref, 384 Location obj, 385 uint32_t offset, 386 Location index = Location::NoLocation()); 387 388 // Generate a read barrier for a GC root within `instruction`. 389 // 390 // A read barrier for an object reference GC root is implemented as 391 // a call to the artReadBarrierForRootSlow runtime entry point, 392 // which is passed the value in location `root`: 393 // 394 // mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root); 395 // 396 // The `out` location contains the value returned by 397 // artReadBarrierForRootSlow. 398 void GenerateReadBarrierForRoot(HInstruction* instruction, Location out, Location root); 399 400 int ConstantAreaStart() const { 401 return constant_area_start_; 402 } 403 404 Address LiteralDoubleAddress(double v); 405 Address LiteralFloatAddress(float v); 406 Address LiteralInt32Address(int32_t v); 407 Address LiteralInt64Address(int64_t v); 408 409 // Load a 64 bit value into a register in the most efficient manner. 410 void Load64BitValue(CpuRegister dest, int64_t value); 411 Address LiteralCaseTable(HPackedSwitch* switch_instr); 412 413 // Store a 64 bit value into a DoubleStackSlot in the most efficient manner. 414 void Store64BitValueToStack(Location dest, int64_t value); 415 416 // Assign a 64 bit constant to an address. 417 void MoveInt64ToAddress(const Address& addr_low, 418 const Address& addr_high, 419 int64_t v, 420 HInstruction* instruction); 421 422 private: 423 struct PcRelativeDexCacheAccessInfo { 424 PcRelativeDexCacheAccessInfo(const DexFile& dex_file, uint32_t element_off) 425 : target_dex_file(dex_file), element_offset(element_off), label() { } 426 427 const DexFile& target_dex_file; 428 uint32_t element_offset; 429 Label label; 430 }; 431 432 // Labels for each block that will be compiled. 433 Label* block_labels_; // Indexed by block id. 434 Label frame_entry_label_; 435 LocationsBuilderX86_64 location_builder_; 436 InstructionCodeGeneratorX86_64 instruction_visitor_; 437 ParallelMoveResolverX86_64 move_resolver_; 438 X86_64Assembler assembler_; 439 const X86_64InstructionSetFeatures& isa_features_; 440 441 // Offset to the start of the constant area in the assembled code. 442 // Used for fixups to the constant area. 443 int constant_area_start_; 444 445 // Method patch info. Using ArenaDeque<> which retains element addresses on push/emplace_back(). 446 ArenaDeque<MethodPatchInfo<Label>> method_patches_; 447 ArenaDeque<MethodPatchInfo<Label>> relative_call_patches_; 448 // PC-relative DexCache access info. 449 ArenaDeque<PcRelativeDexCacheAccessInfo> pc_relative_dex_cache_patches_; 450 451 // When we don't know the proper offset for the value, we use kDummy32BitOffset. 452 // We will fix this up in the linker later to have the right value. 453 static constexpr int32_t kDummy32BitOffset = 256; 454 455 // Fixups for jump tables need to be handled specially. 456 ArenaVector<JumpTableRIPFixup*> fixups_to_jump_tables_; 457 458 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86_64); 459}; 460 461} // namespace x86_64 462} // namespace art 463 464#endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_64_H_ 465