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 27 namespace art { 28 namespace x86_64 { 29 30 // Use a local definition to prevent copying mistakes. 31 static constexpr size_t kX86_64WordSize = kX86_64PointerSize; 32 33 static constexpr Register kParameterCoreRegisters[] = { RSI, RDX, RCX, R8, R9 }; 34 static constexpr FloatRegister kParameterFloatRegisters[] = 35 { XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7 }; 36 37 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 38 static constexpr size_t kParameterFloatRegistersLength = arraysize(kParameterFloatRegisters); 39 40 static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX, RCX }; 41 static constexpr size_t kRuntimeParameterCoreRegistersLength = 42 arraysize(kRuntimeParameterCoreRegisters); 43 static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1 }; 44 static constexpr size_t kRuntimeParameterFpuRegistersLength = 45 arraysize(kRuntimeParameterFpuRegisters); 46 47 class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> { 48 public: InvokeRuntimeCallingConvention()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 60 class InvokeDexCallingConvention : public CallingConvention<Register, FloatRegister> { 61 public: InvokeDexCallingConvention()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 73 class InvokeDexCallingConventionVisitorX86_64 : public InvokeDexCallingConventionVisitor { 74 public: InvokeDexCallingConventionVisitorX86_64()75 InvokeDexCallingConventionVisitorX86_64() {} ~InvokeDexCallingConventionVisitorX86_64()76 virtual ~InvokeDexCallingConventionVisitorX86_64() {} 77 78 Location GetNextLocation(Primitive::Type type) OVERRIDE; 79 80 private: 81 InvokeDexCallingConvention calling_convention; 82 83 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorX86_64); 84 }; 85 86 class CodeGeneratorX86_64; 87 88 class SlowPathCodeX86_64 : public SlowPathCode { 89 public: SlowPathCodeX86_64()90 SlowPathCodeX86_64() : entry_label_(), exit_label_() {} 91 GetEntryLabel()92 Label* GetEntryLabel() { return &entry_label_; } GetExitLabel()93 Label* GetExitLabel() { return &exit_label_; } 94 95 private: 96 Label entry_label_; 97 Label exit_label_; 98 99 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeX86_64); 100 }; 101 102 class ParallelMoveResolverX86_64 : public ParallelMoveResolverWithSwap { 103 public: ParallelMoveResolverX86_64(ArenaAllocator * allocator,CodeGeneratorX86_64 * codegen)104 ParallelMoveResolverX86_64(ArenaAllocator* allocator, CodeGeneratorX86_64* codegen) 105 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} 106 107 void EmitMove(size_t index) OVERRIDE; 108 void EmitSwap(size_t index) OVERRIDE; 109 void SpillScratch(int reg) OVERRIDE; 110 void RestoreScratch(int reg) OVERRIDE; 111 112 X86_64Assembler* GetAssembler() const; 113 114 private: 115 void Exchange32(CpuRegister reg, int mem); 116 void Exchange32(XmmRegister reg, int mem); 117 void Exchange32(int mem1, int mem2); 118 void Exchange64(CpuRegister reg, int mem); 119 void Exchange64(XmmRegister reg, int mem); 120 void Exchange64(int mem1, int mem2); 121 122 CodeGeneratorX86_64* const codegen_; 123 124 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverX86_64); 125 }; 126 127 class LocationsBuilderX86_64 : public HGraphVisitor { 128 public: LocationsBuilderX86_64(HGraph * graph,CodeGeneratorX86_64 * codegen)129 LocationsBuilderX86_64(HGraph* graph, CodeGeneratorX86_64* codegen) 130 : HGraphVisitor(graph), codegen_(codegen) {} 131 132 #define DECLARE_VISIT_INSTRUCTION(name, super) \ 133 void Visit##name(H##name* instr) OVERRIDE; 134 135 FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION) 136 137 #undef DECLARE_VISIT_INSTRUCTION 138 139 private: 140 void HandleInvoke(HInvoke* invoke); 141 void HandleBitwiseOperation(HBinaryOperation* operation); 142 void HandleShift(HBinaryOperation* operation); 143 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); 144 void HandleFieldGet(HInstruction* instruction); 145 146 CodeGeneratorX86_64* const codegen_; 147 InvokeDexCallingConventionVisitorX86_64 parameter_visitor_; 148 149 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86_64); 150 }; 151 152 class InstructionCodeGeneratorX86_64 : public HGraphVisitor { 153 public: 154 InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen); 155 156 #define DECLARE_VISIT_INSTRUCTION(name, super) \ 157 void Visit##name(H##name* instr) OVERRIDE; 158 FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)159 FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION) 160 161 #undef DECLARE_VISIT_INSTRUCTION 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(SlowPathCodeX86_64* 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, const FieldInfo& field_info); 180 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 181 void GenerateImplicitNullCheck(HNullCheck* instruction); 182 void GenerateExplicitNullCheck(HNullCheck* instruction); 183 void PushOntoFPStack(Location source, uint32_t temp_offset, 184 uint32_t stack_adjustment, bool is_float); 185 void GenerateTestAndBranch(HInstruction* instruction, 186 Label* true_target, 187 Label* false_target, 188 Label* always_true_target); 189 190 X86_64Assembler* const assembler_; 191 CodeGeneratorX86_64* const codegen_; 192 193 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86_64); 194 }; 195 196 class CodeGeneratorX86_64 : public CodeGenerator { 197 public: 198 CodeGeneratorX86_64(HGraph* graph, 199 const X86_64InstructionSetFeatures& isa_features, 200 const CompilerOptions& compiler_options); ~CodeGeneratorX86_64()201 virtual ~CodeGeneratorX86_64() {} 202 203 void GenerateFrameEntry() OVERRIDE; 204 void GenerateFrameExit() OVERRIDE; 205 void Bind(HBasicBlock* block) OVERRIDE; 206 void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; 207 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 208 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 209 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 210 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 211 GetWordSize()212 size_t GetWordSize() const OVERRIDE { 213 return kX86_64WordSize; 214 } 215 GetFloatingPointSpillSlotSize()216 size_t GetFloatingPointSpillSlotSize() const OVERRIDE { 217 return kX86_64WordSize; 218 } 219 GetLocationBuilder()220 HGraphVisitor* GetLocationBuilder() OVERRIDE { 221 return &location_builder_; 222 } 223 GetInstructionVisitor()224 HGraphVisitor* GetInstructionVisitor() OVERRIDE { 225 return &instruction_visitor_; 226 } 227 GetAssembler()228 X86_64Assembler* GetAssembler() OVERRIDE { 229 return &assembler_; 230 } 231 GetMoveResolver()232 ParallelMoveResolverX86_64* GetMoveResolver() OVERRIDE { 233 return &move_resolver_; 234 } 235 GetAddressOf(HBasicBlock * block)236 uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE { 237 return GetLabelOf(block)->Position(); 238 } 239 240 Location GetStackLocation(HLoadLocal* load) const OVERRIDE; 241 242 void SetupBlockedRegisters(bool is_baseline) const OVERRIDE; 243 Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE; 244 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; 245 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; 246 void Finalize(CodeAllocator* allocator) OVERRIDE; 247 GetInstructionSet()248 InstructionSet GetInstructionSet() const OVERRIDE { 249 return InstructionSet::kX86_64; 250 } 251 252 // Emit a write barrier. 253 void MarkGCCard(CpuRegister temp, CpuRegister card, CpuRegister object, CpuRegister value); 254 255 // Helper method to move a value between two locations. 256 void Move(Location destination, Location source); 257 258 void LoadCurrentMethod(CpuRegister reg); 259 GetLabelOf(HBasicBlock * block)260 Label* GetLabelOf(HBasicBlock* block) const { 261 return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block); 262 } 263 Initialize()264 void Initialize() OVERRIDE { 265 block_labels_.SetSize(GetGraph()->GetBlocks().Size()); 266 } 267 NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED)268 bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 269 return false; 270 } 271 272 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, CpuRegister temp); 273 GetInstructionSetFeatures()274 const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const { 275 return isa_features_; 276 } 277 ConstantAreaStart()278 int ConstantAreaStart() const { 279 return constant_area_start_; 280 } 281 282 Address LiteralDoubleAddress(double v); 283 Address LiteralFloatAddress(float v); 284 Address LiteralInt32Address(int32_t v); 285 Address LiteralInt64Address(int64_t v); 286 287 // Load a 64 bit value into a register in the most efficient manner. 288 void Load64BitValue(CpuRegister dest, int64_t value); 289 290 private: 291 // Labels for each block that will be compiled. 292 GrowableArray<Label> block_labels_; 293 Label frame_entry_label_; 294 LocationsBuilderX86_64 location_builder_; 295 InstructionCodeGeneratorX86_64 instruction_visitor_; 296 ParallelMoveResolverX86_64 move_resolver_; 297 X86_64Assembler assembler_; 298 const X86_64InstructionSetFeatures& isa_features_; 299 300 // Offset to the start of the constant area in the assembled code. 301 // Used for fixups to the constant area. 302 int constant_area_start_; 303 304 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86_64); 305 }; 306 307 } // namespace x86_64 308 } // namespace art 309 310 #endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_64_H_ 311