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_ARM_H_ 18#define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_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/arm/assembler_thumb2.h" 26 27namespace art { 28namespace arm { 29 30class CodeGeneratorARM; 31class SlowPathCodeARM; 32 33// Use a local definition to prevent copying mistakes. 34static constexpr size_t kArmWordSize = kArmPointerSize; 35static constexpr size_t kArmBitsPerWord = kArmWordSize * kBitsPerByte; 36 37static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 }; 38static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 39static constexpr SRegister kParameterFpuRegisters[] = 40 { S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15 }; 41static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters); 42 43static constexpr Register kArtMethodRegister = R0; 44 45static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 }; 46static constexpr size_t kRuntimeParameterCoreRegistersLength = 47 arraysize(kRuntimeParameterCoreRegisters); 48static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1, S2, S3 }; 49static constexpr size_t kRuntimeParameterFpuRegistersLength = 50 arraysize(kRuntimeParameterFpuRegisters); 51 52class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> { 53 public: 54 InvokeRuntimeCallingConvention() 55 : CallingConvention(kRuntimeParameterCoreRegisters, 56 kRuntimeParameterCoreRegistersLength, 57 kRuntimeParameterFpuRegisters, 58 kRuntimeParameterFpuRegistersLength, 59 kArmPointerSize) {} 60 61 private: 62 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 63}; 64 65static constexpr DRegister FromLowSToD(SRegister reg) { 66 return DCHECK_CONSTEXPR(reg % 2 == 0, , D0) 67 static_cast<DRegister>(reg / 2); 68} 69 70 71class InvokeDexCallingConvention : public CallingConvention<Register, SRegister> { 72 public: 73 InvokeDexCallingConvention() 74 : CallingConvention(kParameterCoreRegisters, 75 kParameterCoreRegistersLength, 76 kParameterFpuRegisters, 77 kParameterFpuRegistersLength, 78 kArmPointerSize) {} 79 80 private: 81 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); 82}; 83 84class InvokeDexCallingConventionVisitorARM : public InvokeDexCallingConventionVisitor { 85 public: 86 InvokeDexCallingConventionVisitorARM() {} 87 virtual ~InvokeDexCallingConventionVisitorARM() {} 88 89 Location GetNextLocation(Primitive::Type type) OVERRIDE; 90 Location GetReturnLocation(Primitive::Type type); 91 92 private: 93 InvokeDexCallingConvention calling_convention; 94 uint32_t double_index_ = 0; 95 96 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorARM); 97}; 98 99class ParallelMoveResolverARM : public ParallelMoveResolverWithSwap { 100 public: 101 ParallelMoveResolverARM(ArenaAllocator* allocator, CodeGeneratorARM* codegen) 102 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} 103 104 void EmitMove(size_t index) OVERRIDE; 105 void EmitSwap(size_t index) OVERRIDE; 106 void SpillScratch(int reg) OVERRIDE; 107 void RestoreScratch(int reg) OVERRIDE; 108 109 ArmAssembler* GetAssembler() const; 110 111 private: 112 void Exchange(Register reg, int mem); 113 void Exchange(int mem1, int mem2); 114 115 CodeGeneratorARM* const codegen_; 116 117 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverARM); 118}; 119 120class SlowPathCodeARM : public SlowPathCode { 121 public: 122 SlowPathCodeARM() : entry_label_(), exit_label_() {} 123 124 Label* GetEntryLabel() { return &entry_label_; } 125 Label* GetExitLabel() { return &exit_label_; } 126 127 private: 128 Label entry_label_; 129 Label exit_label_; 130 131 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM); 132}; 133 134class LocationsBuilderARM : public HGraphVisitor { 135 public: 136 LocationsBuilderARM(HGraph* graph, CodeGeneratorARM* codegen) 137 : HGraphVisitor(graph), codegen_(codegen) {} 138 139#define DECLARE_VISIT_INSTRUCTION(name, super) \ 140 void Visit##name(H##name* instr); 141 142 FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION) 143 144#undef DECLARE_VISIT_INSTRUCTION 145 146 private: 147 void HandleInvoke(HInvoke* invoke); 148 void HandleBitwiseOperation(HBinaryOperation* operation); 149 void HandleShift(HBinaryOperation* operation); 150 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); 151 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 152 153 CodeGeneratorARM* const codegen_; 154 InvokeDexCallingConventionVisitorARM parameter_visitor_; 155 156 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM); 157}; 158 159class InstructionCodeGeneratorARM : public HGraphVisitor { 160 public: 161 InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen); 162 163#define DECLARE_VISIT_INSTRUCTION(name, super) \ 164 void Visit##name(H##name* instr); 165 166 FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION) 167 168#undef DECLARE_VISIT_INSTRUCTION 169 170 ArmAssembler* GetAssembler() const { return assembler_; } 171 172 private: 173 // Generate code for the given suspend check. If not null, `successor` 174 // is the block to branch to if the suspend check is not needed, and after 175 // the suspend call. 176 void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); 177 void GenerateClassInitializationCheck(SlowPathCodeARM* slow_path, Register class_reg); 178 void HandleBitwiseOperation(HBinaryOperation* operation); 179 void HandleShift(HBinaryOperation* operation); 180 void GenerateMemoryBarrier(MemBarrierKind kind); 181 void GenerateWideAtomicStore(Register addr, uint32_t offset, 182 Register value_lo, Register value_hi, 183 Register temp1, Register temp2, 184 HInstruction* instruction); 185 void GenerateWideAtomicLoad(Register addr, uint32_t offset, 186 Register out_lo, Register out_hi); 187 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); 188 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 189 void GenerateImplicitNullCheck(HNullCheck* instruction); 190 void GenerateExplicitNullCheck(HNullCheck* instruction); 191 void GenerateTestAndBranch(HInstruction* instruction, 192 Label* true_target, 193 Label* false_target, 194 Label* always_true_target); 195 196 ArmAssembler* const assembler_; 197 CodeGeneratorARM* const codegen_; 198 199 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorARM); 200}; 201 202class CodeGeneratorARM : public CodeGenerator { 203 public: 204 CodeGeneratorARM(HGraph* graph, 205 const ArmInstructionSetFeatures& isa_features, 206 const CompilerOptions& compiler_options); 207 virtual ~CodeGeneratorARM() {} 208 209 void GenerateFrameEntry() OVERRIDE; 210 void GenerateFrameExit() OVERRIDE; 211 void Bind(HBasicBlock* block) OVERRIDE; 212 void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; 213 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 214 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 215 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 216 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 217 218 size_t GetWordSize() const OVERRIDE { 219 return kArmWordSize; 220 } 221 222 size_t GetFloatingPointSpillSlotSize() const OVERRIDE { 223 // Allocated in S registers, which are word sized. 224 return kArmWordSize; 225 } 226 227 HGraphVisitor* GetLocationBuilder() OVERRIDE { 228 return &location_builder_; 229 } 230 231 HGraphVisitor* GetInstructionVisitor() OVERRIDE { 232 return &instruction_visitor_; 233 } 234 235 ArmAssembler* GetAssembler() OVERRIDE { 236 return &assembler_; 237 } 238 239 uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE { 240 return GetLabelOf(block)->Position(); 241 } 242 243 void SetupBlockedRegisters(bool is_baseline) const OVERRIDE; 244 245 Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE; 246 247 Location GetStackLocation(HLoadLocal* load) const OVERRIDE; 248 249 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; 250 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; 251 252 // Blocks all register pairs made out of blocked core registers. 253 void UpdateBlockedPairRegisters() const; 254 255 ParallelMoveResolverARM* GetMoveResolver() OVERRIDE { 256 return &move_resolver_; 257 } 258 259 InstructionSet GetInstructionSet() const OVERRIDE { 260 return InstructionSet::kThumb2; 261 } 262 263 // Helper method to move a 32bits value between two locations. 264 void Move32(Location destination, Location source); 265 // Helper method to move a 64bits value between two locations. 266 void Move64(Location destination, Location source); 267 268 // Load current method into `reg`. 269 void LoadCurrentMethod(Register reg); 270 271 // Generate code to invoke a runtime entry point. 272 void InvokeRuntime( 273 int32_t offset, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path); 274 275 // Emit a write barrier. 276 void MarkGCCard(Register temp, Register card, Register object, Register value); 277 278 Label* GetLabelOf(HBasicBlock* block) const { 279 return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block); 280 } 281 282 void Initialize() OVERRIDE { 283 block_labels_.SetSize(GetGraph()->GetBlocks().Size()); 284 } 285 286 const ArmInstructionSetFeatures& GetInstructionSetFeatures() const { 287 return isa_features_; 288 } 289 290 bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE { 291 return type == Primitive::kPrimDouble || type == Primitive::kPrimLong; 292 } 293 294 void ComputeSpillMask() OVERRIDE; 295 296 Label* GetFrameEntryLabel() { return &frame_entry_label_; } 297 298 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp); 299 300 private: 301 // Labels for each block that will be compiled. 302 GrowableArray<Label> block_labels_; 303 Label frame_entry_label_; 304 LocationsBuilderARM location_builder_; 305 InstructionCodeGeneratorARM instruction_visitor_; 306 ParallelMoveResolverARM move_resolver_; 307 Thumb2Assembler assembler_; 308 const ArmInstructionSetFeatures& isa_features_; 309 310 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM); 311}; 312 313} // namespace arm 314} // namespace art 315 316#endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_H_ 317