1 /* 2 * Copyright (C) 2015 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_MIPS_H_ 18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS_H_ 19 20 #include "code_generator.h" 21 #include "dex_file_types.h" 22 #include "driver/compiler_options.h" 23 #include "nodes.h" 24 #include "parallel_move_resolver.h" 25 #include "string_reference.h" 26 #include "type_reference.h" 27 #include "utils/mips/assembler_mips.h" 28 29 namespace art { 30 namespace mips { 31 32 // InvokeDexCallingConvention registers 33 34 static constexpr Register kParameterCoreRegisters[] = 35 { A1, A2, A3, T0, T1 }; 36 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 37 38 static constexpr FRegister kParameterFpuRegisters[] = 39 { F8, F10, F12, F14, F16, F18 }; 40 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters); 41 42 43 // InvokeRuntimeCallingConvention registers 44 45 static constexpr Register kRuntimeParameterCoreRegisters[] = 46 { A0, A1, A2, A3 }; 47 static constexpr size_t kRuntimeParameterCoreRegistersLength = 48 arraysize(kRuntimeParameterCoreRegisters); 49 50 static constexpr FRegister kRuntimeParameterFpuRegisters[] = 51 { F12, F14 }; 52 static constexpr size_t kRuntimeParameterFpuRegistersLength = 53 arraysize(kRuntimeParameterFpuRegisters); 54 55 56 static constexpr Register kCoreCalleeSaves[] = 57 { S0, S1, S2, S3, S4, S5, S6, S7, FP, RA }; 58 static constexpr FRegister kFpuCalleeSaves[] = 59 { F20, F22, F24, F26, F28, F30 }; 60 61 62 class CodeGeneratorMIPS; 63 64 VectorRegister VectorRegisterFrom(Location location); 65 66 class InvokeDexCallingConvention : public CallingConvention<Register, FRegister> { 67 public: InvokeDexCallingConvention()68 InvokeDexCallingConvention() 69 : CallingConvention(kParameterCoreRegisters, 70 kParameterCoreRegistersLength, 71 kParameterFpuRegisters, 72 kParameterFpuRegistersLength, 73 kMipsPointerSize) {} 74 75 private: 76 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); 77 }; 78 79 class InvokeDexCallingConventionVisitorMIPS : public InvokeDexCallingConventionVisitor { 80 public: InvokeDexCallingConventionVisitorMIPS()81 InvokeDexCallingConventionVisitorMIPS() {} ~InvokeDexCallingConventionVisitorMIPS()82 virtual ~InvokeDexCallingConventionVisitorMIPS() {} 83 84 Location GetNextLocation(Primitive::Type type) OVERRIDE; 85 Location GetReturnLocation(Primitive::Type type) const OVERRIDE; 86 Location GetMethodLocation() const OVERRIDE; 87 88 private: 89 InvokeDexCallingConvention calling_convention; 90 91 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorMIPS); 92 }; 93 94 class InvokeRuntimeCallingConvention : public CallingConvention<Register, FRegister> { 95 public: InvokeRuntimeCallingConvention()96 InvokeRuntimeCallingConvention() 97 : CallingConvention(kRuntimeParameterCoreRegisters, 98 kRuntimeParameterCoreRegistersLength, 99 kRuntimeParameterFpuRegisters, 100 kRuntimeParameterFpuRegistersLength, 101 kMipsPointerSize) {} 102 103 Location GetReturnLocation(Primitive::Type return_type); 104 105 private: 106 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 107 }; 108 109 class FieldAccessCallingConventionMIPS : public FieldAccessCallingConvention { 110 public: FieldAccessCallingConventionMIPS()111 FieldAccessCallingConventionMIPS() {} 112 GetObjectLocation()113 Location GetObjectLocation() const OVERRIDE { 114 return Location::RegisterLocation(A1); 115 } GetFieldIndexLocation()116 Location GetFieldIndexLocation() const OVERRIDE { 117 return Location::RegisterLocation(A0); 118 } GetReturnLocation(Primitive::Type type)119 Location GetReturnLocation(Primitive::Type type) const OVERRIDE { 120 return Primitive::Is64BitType(type) 121 ? Location::RegisterPairLocation(V0, V1) 122 : Location::RegisterLocation(V0); 123 } GetSetValueLocation(Primitive::Type type,bool is_instance)124 Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE { 125 return Primitive::Is64BitType(type) 126 ? Location::RegisterPairLocation(A2, A3) 127 : (is_instance ? Location::RegisterLocation(A2) : Location::RegisterLocation(A1)); 128 } GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED)129 Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 130 return Location::FpuRegisterLocation(F0); 131 } 132 133 private: 134 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionMIPS); 135 }; 136 137 class ParallelMoveResolverMIPS : public ParallelMoveResolverWithSwap { 138 public: ParallelMoveResolverMIPS(ArenaAllocator * allocator,CodeGeneratorMIPS * codegen)139 ParallelMoveResolverMIPS(ArenaAllocator* allocator, CodeGeneratorMIPS* codegen) 140 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} 141 142 void EmitMove(size_t index) OVERRIDE; 143 void EmitSwap(size_t index) OVERRIDE; 144 void SpillScratch(int reg) OVERRIDE; 145 void RestoreScratch(int reg) OVERRIDE; 146 147 void Exchange(int index1, int index2, bool double_slot); 148 149 MipsAssembler* GetAssembler() const; 150 151 private: 152 CodeGeneratorMIPS* const codegen_; 153 154 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverMIPS); 155 }; 156 157 class SlowPathCodeMIPS : public SlowPathCode { 158 public: SlowPathCodeMIPS(HInstruction * instruction)159 explicit SlowPathCodeMIPS(HInstruction* instruction) 160 : SlowPathCode(instruction), entry_label_(), exit_label_() {} 161 GetEntryLabel()162 MipsLabel* GetEntryLabel() { return &entry_label_; } GetExitLabel()163 MipsLabel* GetExitLabel() { return &exit_label_; } 164 165 private: 166 MipsLabel entry_label_; 167 MipsLabel exit_label_; 168 169 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeMIPS); 170 }; 171 172 class LocationsBuilderMIPS : public HGraphVisitor { 173 public: LocationsBuilderMIPS(HGraph * graph,CodeGeneratorMIPS * codegen)174 LocationsBuilderMIPS(HGraph* graph, CodeGeneratorMIPS* codegen) 175 : HGraphVisitor(graph), codegen_(codegen) {} 176 177 #define DECLARE_VISIT_INSTRUCTION(name, super) \ 178 void Visit##name(H##name* instr) OVERRIDE; 179 180 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_MIPS(DECLARE_VISIT_INSTRUCTION)181 FOR_EACH_CONCRETE_INSTRUCTION_MIPS(DECLARE_VISIT_INSTRUCTION) 182 183 #undef DECLARE_VISIT_INSTRUCTION 184 185 void VisitInstruction(HInstruction* instruction) OVERRIDE { 186 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 187 << " (id " << instruction->GetId() << ")"; 188 } 189 190 private: 191 void HandleInvoke(HInvoke* invoke); 192 void HandleBinaryOp(HBinaryOperation* operation); 193 void HandleCondition(HCondition* instruction); 194 void HandleShift(HBinaryOperation* operation); 195 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); 196 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 197 Location RegisterOrZeroConstant(HInstruction* instruction); 198 Location FpuRegisterOrConstantForStore(HInstruction* instruction); 199 200 InvokeDexCallingConventionVisitorMIPS parameter_visitor_; 201 202 CodeGeneratorMIPS* const codegen_; 203 204 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderMIPS); 205 }; 206 207 class InstructionCodeGeneratorMIPS : public InstructionCodeGenerator { 208 public: 209 InstructionCodeGeneratorMIPS(HGraph* graph, CodeGeneratorMIPS* codegen); 210 211 #define DECLARE_VISIT_INSTRUCTION(name, super) \ 212 void Visit##name(H##name* instr) OVERRIDE; 213 214 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_MIPS(DECLARE_VISIT_INSTRUCTION)215 FOR_EACH_CONCRETE_INSTRUCTION_MIPS(DECLARE_VISIT_INSTRUCTION) 216 217 #undef DECLARE_VISIT_INSTRUCTION 218 219 void VisitInstruction(HInstruction* instruction) OVERRIDE { 220 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 221 << " (id " << instruction->GetId() << ")"; 222 } 223 GetAssembler()224 MipsAssembler* GetAssembler() const { return assembler_; } 225 226 // Compare-and-jump packed switch generates approx. 3 + 2.5 * N 32-bit 227 // instructions for N cases. 228 // Table-based packed switch generates approx. 11 32-bit instructions 229 // and N 32-bit data words for N cases. 230 // At N = 6 they come out as 18 and 17 32-bit words respectively. 231 // We switch to the table-based method starting with 7 cases. 232 static constexpr uint32_t kPackedSwitchJumpTableThreshold = 6; 233 234 void GenerateMemoryBarrier(MemBarrierKind kind); 235 236 private: 237 void GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path, Register class_reg); 238 void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); 239 void HandleBinaryOp(HBinaryOperation* operation); 240 void HandleCondition(HCondition* instruction); 241 void HandleShift(HBinaryOperation* operation); 242 void HandleFieldSet(HInstruction* instruction, 243 const FieldInfo& field_info, 244 uint32_t dex_pc, 245 bool value_can_be_null); 246 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc); 247 248 // Generate a heap reference load using one register `out`: 249 // 250 // out <- *(out + offset) 251 // 252 // while honoring heap poisoning and/or read barriers (if any). 253 // 254 // Location `maybe_temp` is used when generating a read barrier and 255 // shall be a register in that case; it may be an invalid location 256 // otherwise. 257 void GenerateReferenceLoadOneRegister(HInstruction* instruction, 258 Location out, 259 uint32_t offset, 260 Location maybe_temp, 261 ReadBarrierOption read_barrier_option); 262 // Generate a heap reference load using two different registers 263 // `out` and `obj`: 264 // 265 // out <- *(obj + offset) 266 // 267 // while honoring heap poisoning and/or read barriers (if any). 268 // 269 // Location `maybe_temp` is used when generating a Baker's (fast 270 // path) read barrier and shall be a register in that case; it may 271 // be an invalid location otherwise. 272 void GenerateReferenceLoadTwoRegisters(HInstruction* instruction, 273 Location out, 274 Location obj, 275 uint32_t offset, 276 Location maybe_temp, 277 ReadBarrierOption read_barrier_option); 278 279 // Generate a GC root reference load: 280 // 281 // root <- *(obj + offset) 282 // 283 // while honoring read barriers (if any). 284 void GenerateGcRootFieldLoad(HInstruction* instruction, 285 Location root, 286 Register obj, 287 uint32_t offset, 288 ReadBarrierOption read_barrier_option); 289 290 void GenerateIntCompare(IfCondition cond, LocationSummary* locations); 291 // When the function returns `false` it means that the condition holds if `dst` is non-zero 292 // and doesn't hold if `dst` is zero. If it returns `true`, the roles of zero and non-zero 293 // `dst` are exchanged. 294 bool MaterializeIntCompare(IfCondition cond, 295 LocationSummary* input_locations, 296 Register dst); 297 void GenerateIntCompareAndBranch(IfCondition cond, 298 LocationSummary* locations, 299 MipsLabel* label); 300 void GenerateLongCompare(IfCondition cond, LocationSummary* locations); 301 void GenerateLongCompareAndBranch(IfCondition cond, 302 LocationSummary* locations, 303 MipsLabel* label); 304 void GenerateFpCompare(IfCondition cond, 305 bool gt_bias, 306 Primitive::Type type, 307 LocationSummary* locations); 308 // When the function returns `false` it means that the condition holds if the condition 309 // code flag `cc` is non-zero and doesn't hold if `cc` is zero. If it returns `true`, 310 // the roles of zero and non-zero values of the `cc` flag are exchanged. 311 bool MaterializeFpCompareR2(IfCondition cond, 312 bool gt_bias, 313 Primitive::Type type, 314 LocationSummary* input_locations, 315 int cc); 316 // When the function returns `false` it means that the condition holds if `dst` is non-zero 317 // and doesn't hold if `dst` is zero. If it returns `true`, the roles of zero and non-zero 318 // `dst` are exchanged. 319 bool MaterializeFpCompareR6(IfCondition cond, 320 bool gt_bias, 321 Primitive::Type type, 322 LocationSummary* input_locations, 323 FRegister dst); 324 void GenerateFpCompareAndBranch(IfCondition cond, 325 bool gt_bias, 326 Primitive::Type type, 327 LocationSummary* locations, 328 MipsLabel* label); 329 void GenerateTestAndBranch(HInstruction* instruction, 330 size_t condition_input_index, 331 MipsLabel* true_target, 332 MipsLabel* false_target); 333 void DivRemOneOrMinusOne(HBinaryOperation* instruction); 334 void DivRemByPowerOfTwo(HBinaryOperation* instruction); 335 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); 336 void GenerateDivRemIntegral(HBinaryOperation* instruction); 337 void HandleGoto(HInstruction* got, HBasicBlock* successor); 338 void GenPackedSwitchWithCompares(Register value_reg, 339 int32_t lower_bound, 340 uint32_t num_entries, 341 HBasicBlock* switch_block, 342 HBasicBlock* default_block); 343 void GenTableBasedPackedSwitch(Register value_reg, 344 Register constant_area, 345 int32_t lower_bound, 346 uint32_t num_entries, 347 HBasicBlock* switch_block, 348 HBasicBlock* default_block); 349 350 int32_t VecAddress(LocationSummary* locations, 351 size_t size, 352 /* out */ Register* adjusted_base); 353 void GenConditionalMoveR2(HSelect* select); 354 void GenConditionalMoveR6(HSelect* select); 355 356 MipsAssembler* const assembler_; 357 CodeGeneratorMIPS* const codegen_; 358 359 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorMIPS); 360 }; 361 362 class CodeGeneratorMIPS : public CodeGenerator { 363 public: 364 CodeGeneratorMIPS(HGraph* graph, 365 const MipsInstructionSetFeatures& isa_features, 366 const CompilerOptions& compiler_options, 367 OptimizingCompilerStats* stats = nullptr); ~CodeGeneratorMIPS()368 virtual ~CodeGeneratorMIPS() {} 369 370 void ComputeSpillMask() OVERRIDE; 371 bool HasAllocatedCalleeSaveRegisters() const OVERRIDE; 372 void GenerateFrameEntry() OVERRIDE; 373 void GenerateFrameExit() OVERRIDE; 374 375 void Bind(HBasicBlock* block) OVERRIDE; 376 377 void MoveConstant(Location location, HConstant* c); 378 GetWordSize()379 size_t GetWordSize() const OVERRIDE { return kMipsWordSize; } 380 GetFloatingPointSpillSlotSize()381 size_t GetFloatingPointSpillSlotSize() const OVERRIDE { 382 return GetGraph()->HasSIMD() 383 ? 2 * kMipsDoublewordSize // 16 bytes for each spill. 384 : 1 * kMipsDoublewordSize; // 8 bytes for each spill. 385 } 386 GetAddressOf(HBasicBlock * block)387 uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE { 388 return assembler_.GetLabelLocation(GetLabelOf(block)); 389 } 390 GetLocationBuilder()391 HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } GetInstructionVisitor()392 HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; } GetAssembler()393 MipsAssembler* GetAssembler() OVERRIDE { return &assembler_; } GetAssembler()394 const MipsAssembler& GetAssembler() const OVERRIDE { return assembler_; } 395 396 // Emit linker patches. 397 void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE; 398 void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE; 399 400 // Fast path implementation of ReadBarrier::Barrier for a heap 401 // reference field load when Baker's read barriers are used. 402 void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction, 403 Location ref, 404 Register obj, 405 uint32_t offset, 406 Location temp, 407 bool needs_null_check); 408 // Fast path implementation of ReadBarrier::Barrier for a heap 409 // reference array load when Baker's read barriers are used. 410 void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction, 411 Location ref, 412 Register obj, 413 uint32_t data_offset, 414 Location index, 415 Location temp, 416 bool needs_null_check); 417 418 // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier, 419 // GenerateArrayLoadWithBakerReadBarrier and some intrinsics. 420 // 421 // Load the object reference located at the address 422 // `obj + offset + (index << scale_factor)`, held by object `obj`, into 423 // `ref`, and mark it if needed. 424 // 425 // If `always_update_field` is true, the value of the reference is 426 // atomically updated in the holder (`obj`). 427 void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, 428 Location ref, 429 Register obj, 430 uint32_t offset, 431 Location index, 432 ScaleFactor scale_factor, 433 Location temp, 434 bool needs_null_check, 435 bool always_update_field = false); 436 437 // Generate a read barrier for a heap reference within `instruction` 438 // using a slow path. 439 // 440 // A read barrier for an object reference read from the heap is 441 // implemented as a call to the artReadBarrierSlow runtime entry 442 // point, which is passed the values in locations `ref`, `obj`, and 443 // `offset`: 444 // 445 // mirror::Object* artReadBarrierSlow(mirror::Object* ref, 446 // mirror::Object* obj, 447 // uint32_t offset); 448 // 449 // The `out` location contains the value returned by 450 // artReadBarrierSlow. 451 // 452 // When `index` is provided (i.e. for array accesses), the offset 453 // value passed to artReadBarrierSlow is adjusted to take `index` 454 // into account. 455 void GenerateReadBarrierSlow(HInstruction* instruction, 456 Location out, 457 Location ref, 458 Location obj, 459 uint32_t offset, 460 Location index = Location::NoLocation()); 461 462 // If read barriers are enabled, generate a read barrier for a heap 463 // reference using a slow path. If heap poisoning is enabled, also 464 // unpoison the reference in `out`. 465 void MaybeGenerateReadBarrierSlow(HInstruction* instruction, 466 Location out, 467 Location ref, 468 Location obj, 469 uint32_t offset, 470 Location index = Location::NoLocation()); 471 472 // Generate a read barrier for a GC root within `instruction` using 473 // a slow path. 474 // 475 // A read barrier for an object reference GC root is implemented as 476 // a call to the artReadBarrierForRootSlow runtime entry point, 477 // which is passed the value in location `root`: 478 // 479 // mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root); 480 // 481 // The `out` location contains the value returned by 482 // artReadBarrierForRootSlow. 483 void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root); 484 485 void MarkGCCard(Register object, Register value, bool value_can_be_null); 486 487 // Register allocation. 488 489 void SetupBlockedRegisters() const OVERRIDE; 490 491 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 492 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 493 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 494 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; ClobberRA()495 void ClobberRA() { 496 clobbered_ra_ = true; 497 } 498 499 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; 500 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; 501 GetInstructionSet()502 InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips; } 503 GetInstructionSetFeatures()504 const MipsInstructionSetFeatures& GetInstructionSetFeatures() const { 505 return isa_features_; 506 } 507 GetLabelOf(HBasicBlock * block)508 MipsLabel* GetLabelOf(HBasicBlock* block) const { 509 return CommonGetLabelOf<MipsLabel>(block_labels_, block); 510 } 511 Initialize()512 void Initialize() OVERRIDE { 513 block_labels_ = CommonInitializeLabels<MipsLabel>(); 514 } 515 516 void Finalize(CodeAllocator* allocator) OVERRIDE; 517 518 // Code generation helpers. 519 520 void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE; 521 522 void MoveConstant(Location destination, int32_t value) OVERRIDE; 523 524 void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE; 525 526 // Generate code to invoke a runtime entry point. 527 void InvokeRuntime(QuickEntrypointEnum entrypoint, 528 HInstruction* instruction, 529 uint32_t dex_pc, 530 SlowPathCode* slow_path = nullptr) OVERRIDE; 531 532 // Generate code to invoke a runtime entry point, but do not record 533 // PC-related information in a stack map. 534 void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset, 535 HInstruction* instruction, 536 SlowPathCode* slow_path, 537 bool direct); 538 539 void GenerateInvokeRuntime(int32_t entry_point_offset, bool direct); 540 GetMoveResolver()541 ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; } 542 NeedsTwoRegisters(Primitive::Type type)543 bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE { 544 return type == Primitive::kPrimLong; 545 } 546 547 // Check if the desired_string_load_kind is supported. If it is, return it, 548 // otherwise return a fall-back kind that should be used instead. 549 HLoadString::LoadKind GetSupportedLoadStringKind( 550 HLoadString::LoadKind desired_string_load_kind) OVERRIDE; 551 552 // Check if the desired_class_load_kind is supported. If it is, return it, 553 // otherwise return a fall-back kind that should be used instead. 554 HLoadClass::LoadKind GetSupportedLoadClassKind( 555 HLoadClass::LoadKind desired_class_load_kind) OVERRIDE; 556 557 // Check if the desired_dispatch_info is supported. If it is, return it, 558 // otherwise return a fall-back info that should be used instead. 559 HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( 560 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, 561 HInvokeStaticOrDirect* invoke) OVERRIDE; 562 563 void GenerateStaticOrDirectCall( 564 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE; 565 void GenerateVirtualCall( 566 HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE; 567 MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,Primitive::Type type ATTRIBUTE_UNUSED)568 void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED, 569 Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE { 570 UNIMPLEMENTED(FATAL) << "Not implemented on MIPS"; 571 } 572 573 void GenerateNop() OVERRIDE; 574 void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE; 575 void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE; 576 577 // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays 578 // and boot image strings. The only difference is the interpretation of the offset_or_index. 579 // The 16-bit halves of the 32-bit PC-relative offset are patched separately, necessitating 580 // two patches/infos. There can be more than two patches/infos if the instruction supplying 581 // the high half is shared with e.g. a slow path, while the low half is supplied by separate 582 // instructions, e.g.: 583 // lui r1, high // patch 584 // addu r1, r1, rbase 585 // lw r2, low(r1) // patch 586 // beqz r2, slow_path 587 // back: 588 // ... 589 // slow_path: 590 // ... 591 // sw r2, low(r1) // patch 592 // b back 593 struct PcRelativePatchInfo { PcRelativePatchInfoPcRelativePatchInfo594 PcRelativePatchInfo(const DexFile& dex_file, 595 uint32_t off_or_idx, 596 const PcRelativePatchInfo* info_high) 597 : target_dex_file(dex_file), 598 offset_or_index(off_or_idx), 599 label(), 600 pc_rel_label(), 601 patch_info_high(info_high) { } 602 603 const DexFile& target_dex_file; 604 // Either the dex cache array element offset or the string/type index. 605 uint32_t offset_or_index; 606 // Label for the instruction to patch. 607 MipsLabel label; 608 // Label for the instruction corresponding to PC+0. Not bound or used in low half patches. 609 // Not bound in high half patches on R2 when using HMipsComputeBaseMethodAddress. 610 // Bound in high half patches on R2 when using the NAL instruction instead of 611 // HMipsComputeBaseMethodAddress. 612 // Bound in high half patches on R6. 613 MipsLabel pc_rel_label; 614 // Pointer to the info for the high half patch or nullptr if this is the high half patch info. 615 const PcRelativePatchInfo* patch_info_high; 616 617 private: 618 PcRelativePatchInfo(PcRelativePatchInfo&& other) = delete; 619 DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo); 620 }; 621 622 PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method, 623 const PcRelativePatchInfo* info_high = nullptr); 624 PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method, 625 const PcRelativePatchInfo* info_high = nullptr); 626 PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, 627 dex::TypeIndex type_index, 628 const PcRelativePatchInfo* info_high = nullptr); 629 PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, 630 dex::TypeIndex type_index, 631 const PcRelativePatchInfo* info_high = nullptr); 632 PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file, 633 dex::StringIndex string_index, 634 const PcRelativePatchInfo* info_high = nullptr); 635 Literal* DeduplicateBootImageAddressLiteral(uint32_t address); 636 637 void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high, 638 Register out, 639 Register base, 640 PcRelativePatchInfo* info_low); 641 642 // The JitPatchInfo is used for JIT string and class loads. 643 struct JitPatchInfo { JitPatchInfoJitPatchInfo644 JitPatchInfo(const DexFile& dex_file, uint64_t idx) 645 : target_dex_file(dex_file), index(idx) { } 646 JitPatchInfo(JitPatchInfo&& other) = default; 647 648 const DexFile& target_dex_file; 649 // String/type index. 650 uint64_t index; 651 // Label for the instruction loading the most significant half of the address. 652 // The least significant half is loaded with the instruction that follows immediately. 653 MipsLabel high_label; 654 }; 655 656 void PatchJitRootUse(uint8_t* code, 657 const uint8_t* roots_data, 658 const JitPatchInfo& info, 659 uint64_t index_in_table) const; 660 JitPatchInfo* NewJitRootStringPatch(const DexFile& dex_file, 661 dex::StringIndex dex_index, 662 Handle<mirror::String> handle); 663 JitPatchInfo* NewJitRootClassPatch(const DexFile& dex_file, 664 dex::TypeIndex dex_index, 665 Handle<mirror::Class> handle); 666 667 private: 668 Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp); 669 670 using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, Literal*>; 671 672 Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map); 673 PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file, 674 uint32_t offset_or_index, 675 const PcRelativePatchInfo* info_high, 676 ArenaDeque<PcRelativePatchInfo>* patches); 677 678 template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)> 679 void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos, 680 ArenaVector<LinkerPatch>* linker_patches); 681 682 // Labels for each block that will be compiled. 683 MipsLabel* block_labels_; 684 MipsLabel frame_entry_label_; 685 LocationsBuilderMIPS location_builder_; 686 InstructionCodeGeneratorMIPS instruction_visitor_; 687 ParallelMoveResolverMIPS move_resolver_; 688 MipsAssembler assembler_; 689 const MipsInstructionSetFeatures& isa_features_; 690 691 // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. 692 Uint32ToLiteralMap uint32_literals_; 693 // PC-relative method patch info for kBootImageLinkTimePcRelative. 694 ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_; 695 // PC-relative method patch info for kBssEntry. 696 ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_; 697 // PC-relative type patch info for kBootImageLinkTimePcRelative. 698 ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_; 699 // PC-relative type patch info for kBssEntry. 700 ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_; 701 // PC-relative String patch info; type depends on configuration (app .bss or boot image PIC). 702 ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_; 703 704 // Patches for string root accesses in JIT compiled code. 705 ArenaDeque<JitPatchInfo> jit_string_patches_; 706 // Patches for class root accesses in JIT compiled code. 707 ArenaDeque<JitPatchInfo> jit_class_patches_; 708 709 // PC-relative loads on R2 clobber RA, which may need to be preserved explicitly in leaf methods. 710 // This is a flag set by pc_relative_fixups_mips and dex_cache_array_fixups_mips optimizations. 711 bool clobbered_ra_; 712 713 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorMIPS); 714 }; 715 716 } // namespace mips 717 } // namespace art 718 719 #endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS_H_ 720