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