code_generator_x86_64.h revision cfa410b0ea561318f74a76c5323f0f6cd8eaaa50
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 SlowPathCodeX86_64 : public SlowPathCode { 91 public: 92 SlowPathCodeX86_64() : entry_label_(), exit_label_() {} 93 94 Label* GetEntryLabel() { return &entry_label_; } 95 Label* GetExitLabel() { return &exit_label_; } 96 97 private: 98 Label entry_label_; 99 Label exit_label_; 100 101 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeX86_64); 102}; 103 104class ParallelMoveResolverX86_64 : public ParallelMoveResolverWithSwap { 105 public: 106 ParallelMoveResolverX86_64(ArenaAllocator* allocator, CodeGeneratorX86_64* codegen) 107 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} 108 109 void EmitMove(size_t index) OVERRIDE; 110 void EmitSwap(size_t index) OVERRIDE; 111 void SpillScratch(int reg) OVERRIDE; 112 void RestoreScratch(int reg) OVERRIDE; 113 114 X86_64Assembler* GetAssembler() const; 115 116 private: 117 void Exchange32(CpuRegister reg, int mem); 118 void Exchange32(XmmRegister reg, int mem); 119 void Exchange32(int mem1, int mem2); 120 void Exchange64(CpuRegister reg, int mem); 121 void Exchange64(XmmRegister reg, int mem); 122 void Exchange64(int mem1, int mem2); 123 124 CodeGeneratorX86_64* const codegen_; 125 126 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverX86_64); 127}; 128 129class LocationsBuilderX86_64 : public HGraphVisitor { 130 public: 131 LocationsBuilderX86_64(HGraph* graph, CodeGeneratorX86_64* codegen) 132 : HGraphVisitor(graph), codegen_(codegen) {} 133 134#define DECLARE_VISIT_INSTRUCTION(name, super) \ 135 void Visit##name(H##name* instr) OVERRIDE; 136 137 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) 138 FOR_EACH_CONCRETE_INSTRUCTION_X86_64(DECLARE_VISIT_INSTRUCTION) 139 140#undef DECLARE_VISIT_INSTRUCTION 141 142 void VisitInstruction(HInstruction* instruction) OVERRIDE { 143 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 144 << " (id " << instruction->GetId() << ")"; 145 } 146 147 private: 148 void HandleInvoke(HInvoke* invoke); 149 void HandleBitwiseOperation(HBinaryOperation* operation); 150 void HandleShift(HBinaryOperation* operation); 151 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); 152 void HandleFieldGet(HInstruction* instruction); 153 154 CodeGeneratorX86_64* const codegen_; 155 InvokeDexCallingConventionVisitorX86_64 parameter_visitor_; 156 157 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86_64); 158}; 159 160class InstructionCodeGeneratorX86_64 : public HGraphVisitor { 161 public: 162 InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen); 163 164#define DECLARE_VISIT_INSTRUCTION(name, super) \ 165 void Visit##name(H##name* instr) OVERRIDE; 166 167 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) 168 FOR_EACH_CONCRETE_INSTRUCTION_X86_64(DECLARE_VISIT_INSTRUCTION) 169 170#undef DECLARE_VISIT_INSTRUCTION 171 172 void VisitInstruction(HInstruction* instruction) OVERRIDE { 173 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 174 << " (id " << instruction->GetId() << ")"; 175 } 176 177 X86_64Assembler* GetAssembler() const { return assembler_; } 178 179 private: 180 // Generate code for the given suspend check. If not null, `successor` 181 // is the block to branch to if the suspend check is not needed, and after 182 // the suspend call. 183 void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); 184 void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg); 185 void HandleBitwiseOperation(HBinaryOperation* operation); 186 void GenerateRemFP(HRem* rem); 187 void DivRemOneOrMinusOne(HBinaryOperation* instruction); 188 void DivByPowerOfTwo(HDiv* instruction); 189 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); 190 void GenerateDivRemIntegral(HBinaryOperation* instruction); 191 void HandleShift(HBinaryOperation* operation); 192 void GenerateMemoryBarrier(MemBarrierKind kind); 193 void HandleFieldSet(HInstruction* instruction, 194 const FieldInfo& field_info, 195 bool value_can_be_null); 196 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 197 void GenerateImplicitNullCheck(HNullCheck* instruction); 198 void GenerateExplicitNullCheck(HNullCheck* instruction); 199 void PushOntoFPStack(Location source, uint32_t temp_offset, 200 uint32_t stack_adjustment, bool is_float); 201 void GenerateTestAndBranch(HInstruction* instruction, 202 Label* true_target, 203 Label* false_target, 204 Label* always_true_target); 205 void GenerateCompareTestAndBranch(HIf* if_inst, 206 HCondition* condition, 207 Label* true_target, 208 Label* false_target, 209 Label* always_true_target); 210 void GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label); 211 void HandleGoto(HInstruction* got, HBasicBlock* successor); 212 213 X86_64Assembler* const assembler_; 214 CodeGeneratorX86_64* const codegen_; 215 216 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86_64); 217}; 218 219class CodeGeneratorX86_64 : public CodeGenerator { 220 public: 221 CodeGeneratorX86_64(HGraph* graph, 222 const X86_64InstructionSetFeatures& isa_features, 223 const CompilerOptions& compiler_options); 224 virtual ~CodeGeneratorX86_64() {} 225 226 void GenerateFrameEntry() OVERRIDE; 227 void GenerateFrameExit() OVERRIDE; 228 void Bind(HBasicBlock* block) OVERRIDE; 229 void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; 230 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 231 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 232 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 233 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 234 235 // Generate code to invoke a runtime entry point. 236 void InvokeRuntime(Address entry_point, 237 HInstruction* instruction, 238 uint32_t dex_pc, 239 SlowPathCode* slow_path); 240 241 size_t GetWordSize() const OVERRIDE { 242 return kX86_64WordSize; 243 } 244 245 size_t GetFloatingPointSpillSlotSize() const OVERRIDE { 246 return kX86_64WordSize; 247 } 248 249 HGraphVisitor* GetLocationBuilder() OVERRIDE { 250 return &location_builder_; 251 } 252 253 HGraphVisitor* GetInstructionVisitor() OVERRIDE { 254 return &instruction_visitor_; 255 } 256 257 X86_64Assembler* GetAssembler() OVERRIDE { 258 return &assembler_; 259 } 260 261 const X86_64Assembler& GetAssembler() const OVERRIDE { 262 return assembler_; 263 } 264 265 ParallelMoveResolverX86_64* GetMoveResolver() OVERRIDE { 266 return &move_resolver_; 267 } 268 269 uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE { 270 return GetLabelOf(block)->Position(); 271 } 272 273 Location GetStackLocation(HLoadLocal* load) const OVERRIDE; 274 275 void SetupBlockedRegisters(bool is_baseline) const OVERRIDE; 276 Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE; 277 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; 278 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; 279 void Finalize(CodeAllocator* allocator) OVERRIDE; 280 281 InstructionSet GetInstructionSet() const OVERRIDE { 282 return InstructionSet::kX86_64; 283 } 284 285 // Emit a write barrier. 286 void MarkGCCard(CpuRegister temp, 287 CpuRegister card, 288 CpuRegister object, 289 CpuRegister value, 290 bool value_can_be_null); 291 292 // Helper method to move a value between two locations. 293 void Move(Location destination, Location source); 294 295 Label* GetLabelOf(HBasicBlock* block) const { 296 return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block); 297 } 298 299 void Initialize() OVERRIDE { 300 block_labels_.SetSize(GetGraph()->GetBlocks().Size()); 301 } 302 303 bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 304 return false; 305 } 306 307 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp); 308 309 const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const { 310 return isa_features_; 311 } 312 313 int ConstantAreaStart() const { 314 return constant_area_start_; 315 } 316 317 Address LiteralDoubleAddress(double v); 318 Address LiteralFloatAddress(float v); 319 Address LiteralInt32Address(int32_t v); 320 Address LiteralInt64Address(int64_t v); 321 322 // Load a 64 bit value into a register in the most efficient manner. 323 void Load64BitValue(CpuRegister dest, int64_t value); 324 325 // Store a 64 bit value into a DoubleStackSlot in the most efficient manner. 326 void Store64BitValueToStack(Location dest, int64_t value); 327 328 private: 329 // Labels for each block that will be compiled. 330 GrowableArray<Label> block_labels_; 331 Label frame_entry_label_; 332 LocationsBuilderX86_64 location_builder_; 333 InstructionCodeGeneratorX86_64 instruction_visitor_; 334 ParallelMoveResolverX86_64 move_resolver_; 335 X86_64Assembler assembler_; 336 const X86_64InstructionSetFeatures& isa_features_; 337 338 // Offset to the start of the constant area in the assembled code. 339 // Used for fixups to the constant area. 340 int constant_area_start_; 341 342 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86_64); 343}; 344 345} // namespace x86_64 346} // namespace art 347 348#endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_64_H_ 349