1 /* 2 * Copyright (C) 2016 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_VIXL_H_ 18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_VIXL_H_ 19 20 #include "base/enums.h" 21 #include "code_generator.h" 22 #include "common_arm.h" 23 #include "driver/compiler_options.h" 24 #include "nodes.h" 25 #include "string_reference.h" 26 #include "parallel_move_resolver.h" 27 #include "utils/arm/assembler_arm_vixl.h" 28 #include "utils/type_reference.h" 29 30 // TODO(VIXL): make vixl clean wrt -Wshadow. 31 #pragma GCC diagnostic push 32 #pragma GCC diagnostic ignored "-Wshadow" 33 #include "aarch32/constants-aarch32.h" 34 #include "aarch32/instructions-aarch32.h" 35 #include "aarch32/macro-assembler-aarch32.h" 36 #pragma GCC diagnostic pop 37 38 // Default to use the VIXL-based backend on ARM. 39 #ifdef ART_USE_OLD_ARM_BACKEND 40 static constexpr bool kArmUseVIXL32 = false; 41 #else 42 static constexpr bool kArmUseVIXL32 = true; 43 #endif 44 45 namespace art { 46 namespace arm { 47 48 // This constant is used as an approximate margin when emission of veneer and literal pools 49 // must be blocked. 50 static constexpr int kMaxMacroInstructionSizeInBytes = 51 15 * vixl::aarch32::kMaxInstructionSizeInBytes; 52 53 static const vixl::aarch32::Register kParameterCoreRegistersVIXL[] = { 54 vixl::aarch32::r1, 55 vixl::aarch32::r2, 56 vixl::aarch32::r3 57 }; 58 static const size_t kParameterCoreRegistersLengthVIXL = arraysize(kParameterCoreRegistersVIXL); 59 static const vixl::aarch32::SRegister kParameterFpuRegistersVIXL[] = { 60 vixl::aarch32::s0, 61 vixl::aarch32::s1, 62 vixl::aarch32::s2, 63 vixl::aarch32::s3, 64 vixl::aarch32::s4, 65 vixl::aarch32::s5, 66 vixl::aarch32::s6, 67 vixl::aarch32::s7, 68 vixl::aarch32::s8, 69 vixl::aarch32::s9, 70 vixl::aarch32::s10, 71 vixl::aarch32::s11, 72 vixl::aarch32::s12, 73 vixl::aarch32::s13, 74 vixl::aarch32::s14, 75 vixl::aarch32::s15 76 }; 77 static const size_t kParameterFpuRegistersLengthVIXL = arraysize(kParameterFpuRegistersVIXL); 78 79 static const vixl::aarch32::Register kMethodRegister = vixl::aarch32::r0; 80 81 static const vixl::aarch32::Register kCoreAlwaysSpillRegister = vixl::aarch32::r5; 82 83 // Callee saves core registers r5, r6, r7, r8, r10, r11, and lr. 84 static const vixl::aarch32::RegisterList kCoreCalleeSaves = vixl::aarch32::RegisterList::Union( 85 vixl::aarch32::RegisterList(vixl::aarch32::r5, 86 vixl::aarch32::r6, 87 vixl::aarch32::r7, 88 vixl::aarch32::r8), 89 vixl::aarch32::RegisterList(vixl::aarch32::r10, 90 vixl::aarch32::r11, 91 vixl::aarch32::lr)); 92 93 // Callee saves FP registers s16 to s31 inclusive. 94 static const vixl::aarch32::SRegisterList kFpuCalleeSaves = 95 vixl::aarch32::SRegisterList(vixl::aarch32::s16, 16); 96 97 static const vixl::aarch32::Register kRuntimeParameterCoreRegistersVIXL[] = { 98 vixl::aarch32::r0, 99 vixl::aarch32::r1, 100 vixl::aarch32::r2, 101 vixl::aarch32::r3 102 }; 103 static const size_t kRuntimeParameterCoreRegistersLengthVIXL = 104 arraysize(kRuntimeParameterCoreRegistersVIXL); 105 static const vixl::aarch32::SRegister kRuntimeParameterFpuRegistersVIXL[] = { 106 vixl::aarch32::s0, 107 vixl::aarch32::s1, 108 vixl::aarch32::s2, 109 vixl::aarch32::s3 110 }; 111 static const size_t kRuntimeParameterFpuRegistersLengthVIXL = 112 arraysize(kRuntimeParameterFpuRegistersVIXL); 113 114 class LoadClassSlowPathARMVIXL; 115 class CodeGeneratorARMVIXL; 116 117 using VIXLInt32Literal = vixl::aarch32::Literal<int32_t>; 118 using VIXLUInt32Literal = vixl::aarch32::Literal<uint32_t>; 119 120 class JumpTableARMVIXL : public DeletableArenaObject<kArenaAllocSwitchTable> { 121 public: JumpTableARMVIXL(HPackedSwitch * switch_instr)122 explicit JumpTableARMVIXL(HPackedSwitch* switch_instr) 123 : switch_instr_(switch_instr), 124 table_start_(), 125 bb_addresses_(switch_instr->GetArena()->Adapter(kArenaAllocCodeGenerator)) { 126 uint32_t num_entries = switch_instr_->GetNumEntries(); 127 for (uint32_t i = 0; i < num_entries; i++) { 128 VIXLInt32Literal *lit = new VIXLInt32Literal(0, vixl32::RawLiteral::kManuallyPlaced); 129 bb_addresses_.emplace_back(lit); 130 } 131 } 132 GetTableStartLabel()133 vixl::aarch32::Label* GetTableStartLabel() { return &table_start_; } 134 135 void EmitTable(CodeGeneratorARMVIXL* codegen); 136 void FixTable(CodeGeneratorARMVIXL* codegen); 137 138 private: 139 HPackedSwitch* const switch_instr_; 140 vixl::aarch32::Label table_start_; 141 ArenaVector<std::unique_ptr<VIXLInt32Literal>> bb_addresses_; 142 143 DISALLOW_COPY_AND_ASSIGN(JumpTableARMVIXL); 144 }; 145 146 class InvokeRuntimeCallingConventionARMVIXL 147 : public CallingConvention<vixl::aarch32::Register, vixl::aarch32::SRegister> { 148 public: InvokeRuntimeCallingConventionARMVIXL()149 InvokeRuntimeCallingConventionARMVIXL() 150 : CallingConvention(kRuntimeParameterCoreRegistersVIXL, 151 kRuntimeParameterCoreRegistersLengthVIXL, 152 kRuntimeParameterFpuRegistersVIXL, 153 kRuntimeParameterFpuRegistersLengthVIXL, 154 kArmPointerSize) {} 155 156 private: 157 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConventionARMVIXL); 158 }; 159 160 class InvokeDexCallingConventionARMVIXL 161 : public CallingConvention<vixl::aarch32::Register, vixl::aarch32::SRegister> { 162 public: InvokeDexCallingConventionARMVIXL()163 InvokeDexCallingConventionARMVIXL() 164 : CallingConvention(kParameterCoreRegistersVIXL, 165 kParameterCoreRegistersLengthVIXL, 166 kParameterFpuRegistersVIXL, 167 kParameterFpuRegistersLengthVIXL, 168 kArmPointerSize) {} 169 170 private: 171 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionARMVIXL); 172 }; 173 174 class InvokeDexCallingConventionVisitorARMVIXL : public InvokeDexCallingConventionVisitor { 175 public: InvokeDexCallingConventionVisitorARMVIXL()176 InvokeDexCallingConventionVisitorARMVIXL() {} ~InvokeDexCallingConventionVisitorARMVIXL()177 virtual ~InvokeDexCallingConventionVisitorARMVIXL() {} 178 179 Location GetNextLocation(Primitive::Type type) OVERRIDE; 180 Location GetReturnLocation(Primitive::Type type) const OVERRIDE; 181 Location GetMethodLocation() const OVERRIDE; 182 183 private: 184 InvokeDexCallingConventionARMVIXL calling_convention; 185 uint32_t double_index_ = 0; 186 187 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorARMVIXL); 188 }; 189 190 class FieldAccessCallingConventionARMVIXL : public FieldAccessCallingConvention { 191 public: FieldAccessCallingConventionARMVIXL()192 FieldAccessCallingConventionARMVIXL() {} 193 GetObjectLocation()194 Location GetObjectLocation() const OVERRIDE { 195 return helpers::LocationFrom(vixl::aarch32::r1); 196 } GetFieldIndexLocation()197 Location GetFieldIndexLocation() const OVERRIDE { 198 return helpers::LocationFrom(vixl::aarch32::r0); 199 } GetReturnLocation(Primitive::Type type)200 Location GetReturnLocation(Primitive::Type type) const OVERRIDE { 201 return Primitive::Is64BitType(type) 202 ? helpers::LocationFrom(vixl::aarch32::r0, vixl::aarch32::r1) 203 : helpers::LocationFrom(vixl::aarch32::r0); 204 } GetSetValueLocation(Primitive::Type type,bool is_instance)205 Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE { 206 return Primitive::Is64BitType(type) 207 ? helpers::LocationFrom(vixl::aarch32::r2, vixl::aarch32::r3) 208 : (is_instance 209 ? helpers::LocationFrom(vixl::aarch32::r2) 210 : helpers::LocationFrom(vixl::aarch32::r1)); 211 } GetFpuLocation(Primitive::Type type)212 Location GetFpuLocation(Primitive::Type type) const OVERRIDE { 213 return Primitive::Is64BitType(type) 214 ? helpers::LocationFrom(vixl::aarch32::s0, vixl::aarch32::s1) 215 : helpers::LocationFrom(vixl::aarch32::s0); 216 } 217 218 private: 219 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionARMVIXL); 220 }; 221 222 class SlowPathCodeARMVIXL : public SlowPathCode { 223 public: SlowPathCodeARMVIXL(HInstruction * instruction)224 explicit SlowPathCodeARMVIXL(HInstruction* instruction) 225 : SlowPathCode(instruction), entry_label_(), exit_label_() {} 226 GetEntryLabel()227 vixl::aarch32::Label* GetEntryLabel() { return &entry_label_; } GetExitLabel()228 vixl::aarch32::Label* GetExitLabel() { return &exit_label_; } 229 230 void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE; 231 void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE; 232 233 private: 234 vixl::aarch32::Label entry_label_; 235 vixl::aarch32::Label exit_label_; 236 237 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARMVIXL); 238 }; 239 240 class ParallelMoveResolverARMVIXL : public ParallelMoveResolverWithSwap { 241 public: ParallelMoveResolverARMVIXL(ArenaAllocator * allocator,CodeGeneratorARMVIXL * codegen)242 ParallelMoveResolverARMVIXL(ArenaAllocator* allocator, CodeGeneratorARMVIXL* codegen) 243 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} 244 245 void EmitMove(size_t index) OVERRIDE; 246 void EmitSwap(size_t index) OVERRIDE; 247 void SpillScratch(int reg) OVERRIDE; 248 void RestoreScratch(int reg) OVERRIDE; 249 250 ArmVIXLAssembler* GetAssembler() const; 251 252 private: 253 void Exchange(vixl32::Register reg, int mem); 254 void Exchange(int mem1, int mem2); 255 256 CodeGeneratorARMVIXL* const codegen_; 257 258 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverARMVIXL); 259 }; 260 261 class LocationsBuilderARMVIXL : public HGraphVisitor { 262 public: LocationsBuilderARMVIXL(HGraph * graph,CodeGeneratorARMVIXL * codegen)263 LocationsBuilderARMVIXL(HGraph* graph, CodeGeneratorARMVIXL* codegen) 264 : HGraphVisitor(graph), codegen_(codegen) {} 265 266 #define DECLARE_VISIT_INSTRUCTION(name, super) \ 267 void Visit##name(H##name* instr) OVERRIDE; 268 269 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)270 FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION) 271 FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION) 272 273 #undef DECLARE_VISIT_INSTRUCTION 274 275 void VisitInstruction(HInstruction* instruction) OVERRIDE { 276 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 277 << " (id " << instruction->GetId() << ")"; 278 } 279 280 private: 281 void HandleInvoke(HInvoke* invoke); 282 void HandleBitwiseOperation(HBinaryOperation* operation, Opcode opcode); 283 void HandleCondition(HCondition* condition); 284 void HandleIntegerRotate(LocationSummary* locations); 285 void HandleLongRotate(LocationSummary* locations); 286 void HandleShift(HBinaryOperation* operation); 287 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); 288 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 289 290 Location ArithmeticZeroOrFpuRegister(HInstruction* input); 291 Location ArmEncodableConstantOrRegister(HInstruction* constant, Opcode opcode); 292 bool CanEncodeConstantAsImmediate(HConstant* input_cst, Opcode opcode); 293 bool CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode, SetCc set_cc = kCcDontCare); 294 295 CodeGeneratorARMVIXL* const codegen_; 296 InvokeDexCallingConventionVisitorARMVIXL parameter_visitor_; 297 298 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARMVIXL); 299 }; 300 301 class InstructionCodeGeneratorARMVIXL : public InstructionCodeGenerator { 302 public: 303 InstructionCodeGeneratorARMVIXL(HGraph* graph, CodeGeneratorARMVIXL* codegen); 304 305 #define DECLARE_VISIT_INSTRUCTION(name, super) \ 306 void Visit##name(H##name* instr) OVERRIDE; 307 308 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)309 FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION) 310 FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION) 311 312 #undef DECLARE_VISIT_INSTRUCTION 313 314 void VisitInstruction(HInstruction* instruction) OVERRIDE { 315 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 316 << " (id " << instruction->GetId() << ")"; 317 } 318 GetAssembler()319 ArmVIXLAssembler* GetAssembler() const { return assembler_; } GetVIXLAssembler()320 ArmVIXLMacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); } 321 322 private: 323 // Generate code for the given suspend check. If not null, `successor` 324 // is the block to branch to if the suspend check is not needed, and after 325 // the suspend call. 326 void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); 327 void GenerateClassInitializationCheck(LoadClassSlowPathARMVIXL* slow_path, 328 vixl32::Register class_reg); 329 void GenerateAndConst(vixl::aarch32::Register out, vixl::aarch32::Register first, uint32_t value); 330 void GenerateOrrConst(vixl::aarch32::Register out, vixl::aarch32::Register first, uint32_t value); 331 void GenerateEorConst(vixl::aarch32::Register out, vixl::aarch32::Register first, uint32_t value); 332 void GenerateAddLongConst(Location out, Location first, uint64_t value); 333 void HandleBitwiseOperation(HBinaryOperation* operation); 334 void HandleCondition(HCondition* condition); 335 void HandleIntegerRotate(HRor* ror); 336 void HandleLongRotate(HRor* ror); 337 void HandleShift(HBinaryOperation* operation); 338 339 void GenerateWideAtomicStore(vixl::aarch32::Register addr, 340 uint32_t offset, 341 vixl::aarch32::Register value_lo, 342 vixl::aarch32::Register value_hi, 343 vixl::aarch32::Register temp1, 344 vixl::aarch32::Register temp2, 345 HInstruction* instruction); 346 void GenerateWideAtomicLoad(vixl::aarch32::Register addr, 347 uint32_t offset, 348 vixl::aarch32::Register out_lo, 349 vixl::aarch32::Register out_hi); 350 351 void HandleFieldSet(HInstruction* instruction, 352 const FieldInfo& field_info, 353 bool value_can_be_null); 354 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 355 356 // Generate a heap reference load using one register `out`: 357 // 358 // out <- *(out + offset) 359 // 360 // while honoring heap poisoning and/or read barriers (if any). 361 // 362 // Location `maybe_temp` is used when generating a read barrier and 363 // shall be a register in that case; it may be an invalid location 364 // otherwise. 365 void GenerateReferenceLoadOneRegister(HInstruction* instruction, 366 Location out, 367 uint32_t offset, 368 Location maybe_temp, 369 ReadBarrierOption read_barrier_option); 370 // Generate a heap reference load using two different registers 371 // `out` and `obj`: 372 // 373 // out <- *(obj + offset) 374 // 375 // while honoring heap poisoning and/or read barriers (if any). 376 // 377 // Location `maybe_temp` is used when generating a Baker's (fast 378 // path) read barrier and shall be a register in that case; it may 379 // be an invalid location otherwise. 380 void GenerateReferenceLoadTwoRegisters(HInstruction* instruction, 381 Location out, 382 Location obj, 383 uint32_t offset, 384 Location maybe_temp, 385 ReadBarrierOption read_barrier_option); 386 // Generate a GC root reference load: 387 // 388 // root <- *(obj + offset) 389 // 390 // while honoring read barriers based on read_barrier_option. 391 void GenerateGcRootFieldLoad(HInstruction* instruction, 392 Location root, 393 vixl::aarch32::Register obj, 394 uint32_t offset, 395 ReadBarrierOption read_barrier_option); 396 void GenerateTestAndBranch(HInstruction* instruction, 397 size_t condition_input_index, 398 vixl::aarch32::Label* true_target, 399 vixl::aarch32::Label* false_target, 400 bool far_target = true); 401 void GenerateCompareTestAndBranch(HCondition* condition, 402 vixl::aarch32::Label* true_target, 403 vixl::aarch32::Label* false_target); 404 void GenerateLongComparesAndJumps(HCondition* cond, 405 vixl::aarch32::Label* true_label, 406 vixl::aarch32::Label* false_label); 407 void DivRemOneOrMinusOne(HBinaryOperation* instruction); 408 void DivRemByPowerOfTwo(HBinaryOperation* instruction); 409 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); 410 void GenerateDivRemConstantIntegral(HBinaryOperation* instruction); 411 void HandleGoto(HInstruction* got, HBasicBlock* successor); 412 413 ArmVIXLAssembler* const assembler_; 414 CodeGeneratorARMVIXL* const codegen_; 415 416 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorARMVIXL); 417 }; 418 419 class CodeGeneratorARMVIXL : public CodeGenerator { 420 public: 421 CodeGeneratorARMVIXL(HGraph* graph, 422 const ArmInstructionSetFeatures& isa_features, 423 const CompilerOptions& compiler_options, 424 OptimizingCompilerStats* stats = nullptr); ~CodeGeneratorARMVIXL()425 virtual ~CodeGeneratorARMVIXL() {} 426 427 void GenerateFrameEntry() OVERRIDE; 428 void GenerateFrameExit() OVERRIDE; 429 void Bind(HBasicBlock* block) OVERRIDE; 430 void MoveConstant(Location destination, int32_t value) OVERRIDE; 431 void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE; 432 void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE; 433 434 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 435 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 436 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 437 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 438 GetWordSize()439 size_t GetWordSize() const OVERRIDE { 440 return static_cast<size_t>(kArmPointerSize); 441 } 442 GetFloatingPointSpillSlotSize()443 size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return vixl::aarch32::kRegSizeInBytes; } 444 GetLocationBuilder()445 HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } 446 GetInstructionVisitor()447 HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; } 448 GetAssembler()449 ArmVIXLAssembler* GetAssembler() OVERRIDE { return &assembler_; } 450 GetAssembler()451 const ArmVIXLAssembler& GetAssembler() const OVERRIDE { return assembler_; } 452 GetVIXLAssembler()453 ArmVIXLMacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); } 454 GetAddressOf(HBasicBlock * block)455 uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE { 456 vixl::aarch32::Label* block_entry_label = GetLabelOf(block); 457 DCHECK(block_entry_label->IsBound()); 458 return block_entry_label->GetLocation(); 459 } 460 461 void FixJumpTables(); 462 void SetupBlockedRegisters() const OVERRIDE; 463 464 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; 465 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; 466 GetMoveResolver()467 ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; } GetInstructionSet()468 InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kThumb2; } 469 // Helper method to move a 32-bit value between two locations. 470 void Move32(Location destination, Location source); 471 472 void LoadFromShiftedRegOffset(Primitive::Type type, 473 Location out_loc, 474 vixl::aarch32::Register base, 475 vixl::aarch32::Register reg_index, 476 vixl::aarch32::Condition cond = vixl::aarch32::al); 477 void StoreToShiftedRegOffset(Primitive::Type type, 478 Location out_loc, 479 vixl::aarch32::Register base, 480 vixl::aarch32::Register reg_index, 481 vixl::aarch32::Condition cond = vixl::aarch32::al); 482 483 // Generate code to invoke a runtime entry point. 484 void InvokeRuntime(QuickEntrypointEnum entrypoint, 485 HInstruction* instruction, 486 uint32_t dex_pc, 487 SlowPathCode* slow_path = nullptr) OVERRIDE; 488 489 // Generate code to invoke a runtime entry point, but do not record 490 // PC-related information in a stack map. 491 void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset, 492 HInstruction* instruction, 493 SlowPathCode* slow_path); 494 495 // Emit a write barrier. 496 void MarkGCCard(vixl::aarch32::Register temp, 497 vixl::aarch32::Register card, 498 vixl::aarch32::Register object, 499 vixl::aarch32::Register value, 500 bool can_be_null); 501 502 void GenerateMemoryBarrier(MemBarrierKind kind); 503 GetLabelOf(HBasicBlock * block)504 vixl::aarch32::Label* GetLabelOf(HBasicBlock* block) { 505 block = FirstNonEmptyBlock(block); 506 return &(block_labels_[block->GetBlockId()]); 507 } 508 509 vixl32::Label* GetFinalLabel(HInstruction* instruction, vixl32::Label* final_label); 510 Initialize()511 void Initialize() OVERRIDE { 512 block_labels_.resize(GetGraph()->GetBlocks().size()); 513 } 514 515 void Finalize(CodeAllocator* allocator) OVERRIDE; 516 GetInstructionSetFeatures()517 const ArmInstructionSetFeatures& GetInstructionSetFeatures() const { return isa_features_; } 518 NeedsTwoRegisters(Primitive::Type type)519 bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE { 520 return type == Primitive::kPrimDouble || type == Primitive::kPrimLong; 521 } 522 523 void ComputeSpillMask() OVERRIDE; 524 GetFrameEntryLabel()525 vixl::aarch32::Label* GetFrameEntryLabel() { return &frame_entry_label_; } 526 527 // Check if the desired_string_load_kind is supported. If it is, return it, 528 // otherwise return a fall-back kind that should be used instead. 529 HLoadString::LoadKind GetSupportedLoadStringKind( 530 HLoadString::LoadKind desired_string_load_kind) OVERRIDE; 531 532 // Check if the desired_class_load_kind is supported. If it is, return it, 533 // otherwise return a fall-back kind that should be used instead. 534 HLoadClass::LoadKind GetSupportedLoadClassKind( 535 HLoadClass::LoadKind desired_class_load_kind) OVERRIDE; 536 537 // Check if the desired_dispatch_info is supported. If it is, return it, 538 // otherwise return a fall-back info that should be used instead. 539 HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( 540 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, 541 HInvokeStaticOrDirect* invoke) OVERRIDE; 542 543 Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp); 544 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; 545 void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; 546 547 void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE; 548 549 // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays 550 // and boot image strings/types. The only difference is the interpretation of the 551 // offset_or_index. The PC-relative address is loaded with three instructions, 552 // MOVW+MOVT to load the offset to base_reg and then ADD base_reg, PC. The offset 553 // is calculated from the ADD's effective PC, i.e. PC+4 on Thumb2. Though we 554 // currently emit these 3 instructions together, instruction scheduling could 555 // split this sequence apart, so we keep separate labels for each of them. 556 struct PcRelativePatchInfo { PcRelativePatchInfoPcRelativePatchInfo557 PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx) 558 : target_dex_file(dex_file), offset_or_index(off_or_idx) { } 559 PcRelativePatchInfo(PcRelativePatchInfo&& other) = default; 560 561 const DexFile& target_dex_file; 562 // Either the dex cache array element offset or the string/type index. 563 uint32_t offset_or_index; 564 vixl::aarch32::Label movw_label; 565 vixl::aarch32::Label movt_label; 566 vixl::aarch32::Label add_pc_label; 567 }; 568 569 PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file, 570 dex::StringIndex string_index); 571 PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index); 572 PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index); 573 PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, 574 uint32_t element_offset); 575 VIXLUInt32Literal* DeduplicateBootImageStringLiteral(const DexFile& dex_file, 576 dex::StringIndex string_index); 577 VIXLUInt32Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, 578 dex::TypeIndex type_index); 579 VIXLUInt32Literal* DeduplicateBootImageAddressLiteral(uint32_t address); 580 VIXLUInt32Literal* DeduplicateDexCacheAddressLiteral(uint32_t address); 581 VIXLUInt32Literal* DeduplicateJitStringLiteral(const DexFile& dex_file, 582 dex::StringIndex string_index, 583 Handle<mirror::String> handle); 584 VIXLUInt32Literal* DeduplicateJitClassLiteral(const DexFile& dex_file, 585 dex::TypeIndex type_index, 586 Handle<mirror::Class> handle); 587 588 void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE; 589 590 void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE; 591 592 // Fast path implementation of ReadBarrier::Barrier for a heap 593 // reference field load when Baker's read barriers are used. 594 void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction, 595 Location ref, 596 vixl::aarch32::Register obj, 597 uint32_t offset, 598 Location temp, 599 bool needs_null_check); 600 // Fast path implementation of ReadBarrier::Barrier for a heap 601 // reference array load when Baker's read barriers are used. 602 void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction, 603 Location ref, 604 vixl::aarch32::Register obj, 605 uint32_t data_offset, 606 Location index, 607 Location temp, 608 bool needs_null_check); 609 // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier, 610 // GenerateArrayLoadWithBakerReadBarrier and some intrinsics. 611 // 612 // Load the object reference located at the address 613 // `obj + offset + (index << scale_factor)`, held by object `obj`, into 614 // `ref`, and mark it if needed. 615 // 616 // If `always_update_field` is true, the value of the reference is 617 // atomically updated in the holder (`obj`). This operation 618 // requires an extra temporary register, which must be provided as a 619 // non-null pointer (`temp2`). 620 void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, 621 Location ref, 622 vixl::aarch32::Register obj, 623 uint32_t offset, 624 Location index, 625 ScaleFactor scale_factor, 626 Location temp, 627 bool needs_null_check, 628 bool always_update_field = false, 629 vixl::aarch32::Register* temp2 = nullptr); 630 631 // Generate a heap reference load (with no read barrier). 632 void GenerateRawReferenceLoad(HInstruction* instruction, 633 Location ref, 634 vixl::aarch32::Register obj, 635 uint32_t offset, 636 Location index, 637 ScaleFactor scale_factor, 638 bool needs_null_check); 639 640 // Generate a read barrier for a heap reference within `instruction` 641 // using a slow path. 642 // 643 // A read barrier for an object reference read from the heap is 644 // implemented as a call to the artReadBarrierSlow runtime entry 645 // point, which is passed the values in locations `ref`, `obj`, and 646 // `offset`: 647 // 648 // mirror::Object* artReadBarrierSlow(mirror::Object* ref, 649 // mirror::Object* obj, 650 // uint32_t offset); 651 // 652 // The `out` location contains the value returned by 653 // artReadBarrierSlow. 654 // 655 // When `index` is provided (i.e. for array accesses), the offset 656 // value passed to artReadBarrierSlow is adjusted to take `index` 657 // into account. 658 void GenerateReadBarrierSlow(HInstruction* instruction, 659 Location out, 660 Location ref, 661 Location obj, 662 uint32_t offset, 663 Location index = Location::NoLocation()); 664 665 // If read barriers are enabled, generate a read barrier for a heap 666 // reference using a slow path. If heap poisoning is enabled, also 667 // unpoison the reference in `out`. 668 void MaybeGenerateReadBarrierSlow(HInstruction* instruction, 669 Location out, 670 Location ref, 671 Location obj, 672 uint32_t offset, 673 Location index = Location::NoLocation()); 674 675 // Generate a read barrier for a GC root within `instruction` using 676 // a slow path. 677 // 678 // A read barrier for an object reference GC root is implemented as 679 // a call to the artReadBarrierForRootSlow runtime entry point, 680 // which is passed the value in location `root`: 681 // 682 // mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root); 683 // 684 // The `out` location contains the value returned by 685 // artReadBarrierForRootSlow. 686 void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root); 687 688 void GenerateNop() OVERRIDE; 689 690 void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE; 691 void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE; 692 CreateJumpTable(HPackedSwitch * switch_instr)693 JumpTableARMVIXL* CreateJumpTable(HPackedSwitch* switch_instr) { 694 jump_tables_.emplace_back(new (GetGraph()->GetArena()) JumpTableARMVIXL(switch_instr)); 695 return jump_tables_.back().get(); 696 } 697 void EmitJumpTables(); 698 699 void EmitMovwMovtPlaceholder(CodeGeneratorARMVIXL::PcRelativePatchInfo* labels, 700 vixl::aarch32::Register out); 701 702 private: 703 vixl::aarch32::Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, 704 vixl::aarch32::Register temp); 705 706 using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, VIXLUInt32Literal*>; 707 using MethodToLiteralMap = 708 ArenaSafeMap<MethodReference, VIXLUInt32Literal*, MethodReferenceComparator>; 709 using StringToLiteralMap = ArenaSafeMap<StringReference, 710 VIXLUInt32Literal*, 711 StringReferenceValueComparator>; 712 using TypeToLiteralMap = ArenaSafeMap<TypeReference, 713 VIXLUInt32Literal*, 714 TypeReferenceValueComparator>; 715 716 VIXLUInt32Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map); 717 VIXLUInt32Literal* DeduplicateMethodLiteral(MethodReference target_method, 718 MethodToLiteralMap* map); 719 PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file, 720 uint32_t offset_or_index, 721 ArenaDeque<PcRelativePatchInfo>* patches); 722 template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)> 723 static void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos, 724 ArenaVector<LinkerPatch>* linker_patches); 725 726 // Labels for each block that will be compiled. 727 // We use a deque so that the `vixl::aarch32::Label` objects do not move in memory. 728 ArenaDeque<vixl::aarch32::Label> block_labels_; // Indexed by block id. 729 vixl::aarch32::Label frame_entry_label_; 730 731 ArenaVector<std::unique_ptr<JumpTableARMVIXL>> jump_tables_; 732 LocationsBuilderARMVIXL location_builder_; 733 InstructionCodeGeneratorARMVIXL instruction_visitor_; 734 ParallelMoveResolverARMVIXL move_resolver_; 735 736 ArmVIXLAssembler assembler_; 737 const ArmInstructionSetFeatures& isa_features_; 738 739 // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. 740 Uint32ToLiteralMap uint32_literals_; 741 // PC-relative patch info for each HArmDexCacheArraysBase. 742 ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_; 743 // Deduplication map for boot string literals for kBootImageLinkTimeAddress. 744 StringToLiteralMap boot_image_string_patches_; 745 // PC-relative String patch info; type depends on configuration (app .bss or boot image PIC). 746 ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_; 747 // Deduplication map for boot type literals for kBootImageLinkTimeAddress. 748 TypeToLiteralMap boot_image_type_patches_; 749 // PC-relative type patch info for kBootImageLinkTimePcRelative. 750 ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_; 751 // PC-relative type patch info for kBssEntry. 752 ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_; 753 754 // Patches for string literals in JIT compiled code. 755 StringToLiteralMap jit_string_patches_; 756 // Patches for class literals in JIT compiled code. 757 TypeToLiteralMap jit_class_patches_; 758 759 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARMVIXL); 760 }; 761 762 } // namespace arm 763 } // namespace art 764 765 #endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_VIXL_H_ 766