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